About Security
Date | Responsible | Changes |
---|---|---|
December 15, 2022 | @Željko Rumenjak | Initial version |
The core of ledger security is based on asymmetric or public-key cryptography. Besides this, a third-part authentication strategies are also supported by validating JWT bearer tokens. Other aspects of security are covered by a flexible authorization system based on configurable rules, exchanging messages through secure (encrypted) channels and encrypting data at rest.
Asymmetric Cryptography
This is an approach that relies on key pairs, a public and a private key in order to sign messages that are exchanged by the system. Messages are signed by first creating a hash of the message content. It is very important that private keys are kept secret, they should never be shared to anyone. Only a public key is shared to ledger and/or other parties. This allows anyone to validate received messages, but only the owner of the private key can sign new messages.
The model described here makes sure that we can always verify both message integrity and authenticity. If anyone tampers with a message that has been signed, a hash of that message will change and that will invalidate the provided signature. Authenticity of the parties can be verified through key pairs used when signing messages. A new key pair needs to be created for every participant of the system and that allows us to link message signatures to participants of the system.
Non-repudiation is an important aspect of the system that the described security model helps us to enforce. Non-repudiation is a legal concept that refers to an assurance that the sender of the information is provided with proof of delivery and the recipient is provided with proof of sender’s identity. Because of this, neither can later deny having processed the information or performed a certain action.
The primary digital signatures algorithms used by the ledger is ed25519. To learn more about it, see A Deep Dive into Ed25519 Signatures.
Bearer Authentication
Asymmetric cryptography provides the best security guarantees, but in some cases it is impractical to use. This is most commonly noticeable in client facing applications, like websites used for configuration or analytics. In some situations it is acceptable to have a security model which is a bit more flexible. For this purpose we have also supported standard authentication mechanism using JWT bearer tokens.
JWT tokens can be used to carry additional information about the user or request, so we can achieve similar level of security as the explicit signatures used in the asymmetric cryptography model.
Most common use case where pure signatures are impractical is related to data reading operations. In mutation requests the payload or body of the request is hashed and signed. Read API requests don’t contain any body that should be stored in the system, so we cannot use this method to secure the requests. For these use cases we support providing a JWT token with the request that is issued by the client, using its private key. This JWT token may also contain a hash of the entire request which adds an additional security check which prevents anyone from tampering with the data in transit. Single use JWT tokens which include a request hash and are issued using private keys of participants have the same security properties as the signatures described previously.
JWT tokens can be used in a way that is a bit less secure as well. This is useful for less sensitive system operations, but it provides a much better user experience. JWT tokens used this way are multi-use tokens with expiration time. This allows users to login (create their token) and use the same token for all requests in a certain time period. This flow is something users are used to with other services and tools, so it is preferred for direct user interactions. Downside of this approach is that those tokens cannot contain a signed hash of the request and they could be used by attackers until they expire, in case they are leaked. This is usually acceptable for non-critical system operations in most cases.
Ledger also supports third party bearer tokens. This security model allows the system to validate bearer tokens issued by third party authentication systems as well. Those tokens have similar security properties as the multi-use tokens issued using ledger private keys, if the third party issuer is trusted. To configure ledger to accept those tokens it is necessary to register a JWT verification key provided by third party issuer along with any other JWT claims that describe tokens that should be accepted. This model allows for simple integration with third party user management systems which support JWT, for example Auth0, Firebase Auth, GCP Cloud Identity, AWS Cognito, etc.
To learn more about JWT, see JSON Web Token Introduction.
Authorization Rules
Ledger supports granular security controls on all resources using authorization rules. Authorization rules can be configured on every record stored in the ledger, and allow users to declaratively specify security constraints of a record. Authorization rules are part of record payload, this means that they are auditable and signed along with all other record data.
Authorization rules can be defined globally, on the level of an entire ledger. Since all ledger data belongs to a specific ledger instance, ledger level rules allow us to configure security on all records belonging to that ledger instance. This is very useful to setup global security framework of the entire system.
Local authorization rules can also be defined on the level of each record. Those rules allow us to configure more granular access permissions on individual records. The syntax and features of both types of rules is the same, the only difference between them is the scope of records they can target and affect.
Each ledger rules can target a specific ledger operation. It can additionally use any data present in the ledger operation or record for more specific conditions and targeting. Permissions can be granted to specific public keys, signers or bearer tokens.
For more details, see About Authorization.
Secure Communication Channel
Most of ledger communication is performed using HTTPS protocol. HTTPS protocol is a secure version of the HTTP protocol. HTTPS is encrypted in order to increase security of data transfer. The encryption protocol used to encrypt data is called Transport Layer Security (TLS), although formerly it was knows as Secure Sockets Layer (SSL). TLS uses Public Key Infrastructure (PKI) in order to encrypt data. PKI is an asymmetric encryption security system, so it is also used by generating a private and public key pair. A private key in this model is used by the server to decrypt data, and is always kept private, as the name suggests. A public key is shared to users, it is used to encrypt data sent to the server. This means anyone can encrypt data, but only the intended recipient, in our case ledger, can decrypt it.
TLS evolved over time, the latest and most secure version is TLS 1.3. This is the version that is required in order to communicate securely with the ledger over HTTPS.
TLS 1.3 is considered more secure because it eliminates weaker cipher suites, provides perfect forward secrecy, streamlines the handshake process, enhances session resumption, and includes several new security features. These improvements significantly reduce the risk of successful attacks on the communication, making TLS 1.3 the preferred protocol for secure communication over the internet.
To learn more about TLS and related cryptographic principles, see Transport Layer Security.
Data Encryption at Rest
For data encryption at rest we use services provided by Google GCP tools. All databases are provisioned as CloudSQL databases with configured data encryption features. Database backups are also encrypted with their own data encryption keys. Google uses a FIPS 140-2 validated encryption module (certificate 3318) in production environments.
All data is encrypted using the 256-bit Advanced Encryption Standard (AES-256), or better, with symmetric keys: that is, the same key is used to encrypt the data when it is stored, and to decrypt it when it is used. These data keys are themselves encrypted using a key stored in a secure keystore, and changed regularly.
For more details, see Encryption at Rest in Google Cloud.