ullCrypt / encrypted url parameters

 

Goals

Allow user to execute action which would usually require authentication

Use case

Unsubscribe from a mailing list via a link contained in a received newsletter. This process should be as effortless as possible for the user, which means: no login required. However, ullright obviously cannot just offer a link like this:

http://server/unsubscribe/list/1/mail/aatbdotcom

An attacker could easily modify the URL (even if it would be base64-encoded) and unsubscribe someone else.

Suggested solution

Secure parameters

 

Solutions

Secure parameters

ullright has the ability to encrypt/decrypt parameters, resulting in links like this:

http://server/unsubscribe/list/1/s_mail/KJZJEFSGHGHBNNMG

What this feature provides:

  • The value of the parameter is invisible to anyone (though it could be guessed from the parameter name, e.g. a user would assume that a parameter called 's_mail' contained his/her email address).
  • The value of the parameter cannot be modified without the application noticing, changes to the encrypted value are detected.
  • An arbitrary value cannot be made into a valid parameter, e.g. it is not possible for an attacker to fake unsubscription urls.
  • Tampering with the encrypted parameter in any way is detected, i.e. randomly changing some bytes will not result in incorrect decryption, it results in an exception.

What this feature does not provide:

  • Absolute security: Never use this for critical information like passwords or payment information.

How to use

The encryption and decryption is handled transparently for parameter names starting with the prefix s_, for example using 's_mail' as the parameter name would result in automatic en- and decryption of the parameter value. Note that the generated parameters are unique: The parameter value 'test' could result in 'SDFKLSDf' one time and 'KLJK' the next time.

Internal implementation

During encryption, e.g. when using url_for or similar: The ullRouting class (<- sfPatternRouting <- sfRouting) detects and encrypts secure parameters using the ullSecureParameter class.

During decryption, i.e. when the application handles an incoming request: The ullWebRequest class (<- sfWebRequest <- sfRequest) detects and decrypts secure parameters using the ullSecureParameter class.

The ullSecureParameter class uses the ullCrypt class (see below) for anything related to cryptography. Parameters are base64-encoded after encryption and base64-decoded after decryption. The URL-safe variant of base64 is used.

 

Security architecture

Glossary

  • Cleartext: The content which needs protection.
  • Ciphertext: The encrypted form of the cleartext.
  • Cipher: The cryptographic algorithm used, e.g. AES.
  • Key: Data which is used to en- and decrypt cleartext. Needs to be kept secret from anyone not authorized to decrypt.
  • IV: Initialization vector. Usually pseudorandom data which the cipher uses to increase security. The IV used during encryption needs to be known during decryption. It can be transmitted with the ciphertext: it is useless without the key.
  • MAC: Message authentication code. A checksum or tag which provides data integrity as well as authenticity, i.e. it allows for the detection of (malicious or accidental) changes to the ciphertext.
  • HMAC: Hash based MAC. Uses a cryptographic hash function for MAC construction.
     

ullCrypt class

The ullCrypt class is the main class responsible for cryptography in ullright. It is a singleton, which means it should never be instantiated manually but retrieved via the static getInstance() method.

At first construction the class initializes the required cryptography modules (the mcrypt library is used internally) and retrieves the required cryptographic keys via the ullVault class.

Its encrypt() method receives binary data of arbitrary size. First, an IV is generated, then the binary data gets encrypted and the generated IV is prepended to the ciphertext. This data is run through the HMAC generation process (using hash_hmac), and the resulting HMAC is appended to the ciphertext. The final binary data (IV + encrypted data + HMAC) is returned.

The decrypt() method receives binary data of arbitrary size. First the data is checked for minimal length (might throw UnexpectedValueException) and then the given HMAC gets extracted. The expected HMAC is generated and compared to the given HMAC (might throw ullSecurityNotGenuineException). Afterwards the used IV is extracted and the ciphertext is decrypted. The cleartext gets trimmed and returned.

A note concering cleartext trimming: Because ullright uses constant block size for encryption, cleartext is right-padded during encryption and right-trimmed during decryption, using binary zero bytes ('\0'). Developers should be aware of this when encoding 'real' binary data (i.e. not simple strings).

Used algorithms: ullCrypt is configured by default to use Rijndael (= AES) with a key and IV size of 256 bit. The hashing function used for HMAC generation is RIPEMD-160, which generates a 160 bit digest and is also used with a key size of 256 bit.

 

ullVault class

The ullVault class implements the ullVaultInterface, which specifies the getCryptographyKeys(mainKeySize, hashKeySize) method. It returns an associative array with two keys set: mainKey and hashKey, both cut to the sizes specified by the matching method arguments. This class also handles the initial loading of the key from the application's key file.

 

Key management

The main cryptographic key (from which main and hash keys are taken) is stored in the application's 'config' directory under the file name 'ullVault.key'. This file should have appropriate access permissions, e.g. not readable by everyone! They main key is stored as text, base64-encoded. The file must not contain any other content.

The ullright:generate-crypto-key task takes an application name as its only argument. Upon execution the task generates a new key (needs an OpenSSL binary installed) and stores it in the key file. If an old key file exists, it is renamed to security.key.[timestamp].backup, otherwise the file gets created.

Example:  php symfony ullright:generate-crypto-key frontend