Contents

Storing Sensitive Data

What Is It?

Sensitive data can include:

  • Passwords
  • Passphrases
  • Encryption keys
  • OAuth tokens
  • Purchase instruments, such as credit card numbers
  • Personal contact information such as names, phone numbers, email addresses, account usernames, physical addresses, and more
  • Demographic information such as income, gender, age, ethnicity, education
  • In some states and countries: machine identifying information such as MAC address, serial numbers, IP addresses, and more

Sensitive data is also called personally-identifying information (PII) or high business impact (HBI) data. What is considered sensitive data varies greatly from state to state and country to country. Various compliance standards, such as the Payment Card Industry (PCI) compliance standard, require special steps to be taken when collecting sensitive data in order to stay in compliance.

Hardcoded Secrets

Storing sensitive information in the source code of your application might not always be a good practice, anyone that has access to the source code can view the secrets in clear text.

Debug logs

Debug logs in apex code should not contain any sensitive data (usernames, passwords, names, contact information, opportunity information, PII, etc). The debug logs include standard salesforce logs using system.debug() methods or custom debug logs created by the application. Sensitive information should also be not be sent to 3rd party by emails or other means as part of reporting possible errors.

Sensitive Info in URL

Long term secrets like username/passwords, API tokens and long lasting access tokens should not be sent via GET parameters in the query string. It is fine to send short lived tokens like CSRF tokens in the URL. Salesforce session id or any PII data should not be sent over URL to external applications.

Salesforce.com Integrations

External applications should not store Salesforce.com user credentials (usernames, passwords, or session ID's) in external databases. In order to integrate an external application with Salesforce.com user accounts, the OAuth flow should be used. More information about implementing OAuth can be found at here.

Sample Vulnerability

If your application copies and stores sensitive data that originated at salesforce.com, you should take extra precaution. Salesforce.com takes threats to data that originated at their site very seriously, and a data breach or loss could jeopardize your relationship with salesforce.com if you are a partner.

If you must store passwords (including non-Salesforce passwords), note that storing them in plaintext or hashed (such as with the MD5 function) makes your application vulnerable to mass user exploitation if an attacker can get access (even just read-only access) to your database (such as through stealing a backup tape or SQL injection). Although a successful SQL injection or data exposure attack is a huge problem in itself, if the attacker can recover passwords from the data, they can transparently compromise user accounts on a mass scale.

Is My Application Vulnerable?

If your application stores the salesforce.com user password, your application may be vulnerable.

If your application collects other forms of sensitive data, your application may not be compliant with industry standards and the leakage of that sensitive data may cause a significant privacy incident with legal consequences.

How Can I Test My Application?

Review the scheme used to store sensitive data and identify information collected in use cases and workflows.

As PII/HBI data varies from state to state and country to county, it is best to seek expert legal counsel to review sensitive data collected and stored.

How Do I Protect My Application?

Consider an application that must authenticate users. We have to store some form of the user’s password in order to authenticate them, i.e. in order to see if the user presented the correct password. We don’t want to store the password in plaintext form (i.e. unobfuscated or unencrypted), because if an attacker is able to recover the database of passwords (such as by using SQL injection or by stealing a backup tape), they would be able to undetectably hijack every user’s account. Therefore, we want to obfuscate the passwords in such a way that we can still authenticate users.

We could encrypt the passwords, but that would require an encryption key — and where would we store that? We would have to store it in the database or in some other place the application can get it, and then we’re pretty much back where we started: An attacker can recover the plaintext of the passwords by stealing the ciphertexts and the decryption key, and decrypting all the ciphertexts.

(Most or all database-level encryption schemes fall prey to the “But where is the key?” problem. Note that full-disk encryption, as opposed to encrypting database rows or columns with a key known the database client, is a separate and arguably more tractable problem.)

Therefore, developers have historically used a cryptographic hash function, a one-way function that is (supposedly) computationally infeasible to reverse. They then store the hash output:

hash = md5    # or SHA1, or Tiger, or SHA512, etc.
storedPasswordHash = hash(password)

To authenticate users, the application hashes the provided password and compares it to the stored password:

authenticated? = hash(password) == storedPasswordHash

The plaintext password is never stored.

However, there is a problem with this scheme: the attacker can easily pre-compute the hashes of a large password dictionary. Then the attacker matches their hashes to those in their stolen database. For all matches, the attacker has effectively reversed the hash. This technique works as well as the password dictionary is good, and there are some very good password dictionaries out there.

To address this problem, developers have historically “salted” the hash:

salt = generateRandomBytes(2)
storedPasswordHash = salt + hash(salt + password)

The goal is to make attackers have to compute a much larger dictionary of hashes: they now have to compute 2saltSize (e.g. 216 for a 2-byte salt) hashes for each item in their password dictionary.

However, a salted password hash only makes it more expensive to pre-compute the attack against a large password database. It does not protect from attempts to brute force individual passwords when the hash and salt are known. The only obstacle here is the cost of the computing resources required to perform these calculations, and a single round of MD5 or SHA-1 is no longer expensive enough to slow attackers down. Fast, cheap and highly parallel computation on specialized hardware or commodity compute clusters makes brute force search with a dictionary quite affordable and accessible, even to adversaries with few resources. (See Grembowski, referenced above, and http://lastbit.com/gpu.asp and http://arstechnica.com/business/news/2007/10/russian-crackers-throw-gpu-power-at-passwords.ars.)

Therefore, we need a solution that significantly slows down the attacker but does not slow down our application by too much. Fortunately, it turns out this is easy, and there is code to do it. The canonical solution is bcrypt by Niels Provos and David Mazières. The idea is that we tune the hashing function to be pessimal; Provos and Mazières use a modified form of the Blowfish cipher to pessimize its already-slow setup time. Using bcrypt is a fine solution, but it is also easy to build a tunably slow hash function using the standard library of most programming languages.

The benefit of this approach is that it slows down the attacker greatly, but for the application to verify a single password candidate still takes essentially no time. (Additionally, since login actions are such a small fraction of all application traffic, it would still be okay if verification took an entire 0.5 seconds or more.)

How do I protect my application?



Apex and Visualforce Applications

There are multiple ways to protect sensitive data within Force.com, depending on the type of secret being stored, who should have access, and how the secret should be updated.

Protected Custom Metadata Types

Within a namespaced managed package, protected custom metadata types are suitable for storing authentication data and other secrets. Custom metadata types can also be updated via the metadata api in the organization that created the type, and can be read (but not updated) at runtime via SOQL code within an apex class in the same namespace as the metadata type. Secrets which are common across all users of the package (such as an API key) needs to be stored in Managed Protected Custom Metadata Types. Secrets should never be hardcoded in the package code or displayed to the user.

For more information, see the Custom Metadata Implementation Guide

Protected Custom Settings

Custom settings enable application developers to create custom sets of data, as well as create and associate custom data for an organization, profile, or specific user. However, setting the visibility of the Custom Setting Definition to “Protected” and including it in a managed package ensures that it’s only accessible programmatically via Apex code that exists within your package. This is useful for secrets that need to generated at install time or initialized by the admin user.

Unlike custom metadata types, custom settings can be updated at runtime in your Apex class, but cannot be updated via the Metadata Api.

In order to allow authorized users to create and update sensitive information in the UI, create a Visualforce page that only accepts input and does not render the value back on the page. The “transient” keyword should be used to declare instance variables within Visualforce controllers to ensure they are not transmitted as part of the view state. Please refer to the following link for details: transient keyword

Finally, configure the security settings for this page to ensure it’s only accessible by limited profiles on an as needed basis.

For more information, see custom settings methods

Apex Crypto Functions

The Apex crypto class provides algorithms for creating digests, MACs, signatures and AES encryption. When using the crypto functions to implement AES encryption, keys must be generated randomly and stored securely in a Protected Custom Setting or Protected Custom Metadata type. Never hardcode the key in within an Apex class.

For more information and examples for implementing the crypto class, please visit: apex crypto classes

Encrypted Custom Fields

Encrypted custom fields are text fields that can contain letters, numbers, or symbols but are encrypted with 128-bit keys and use the AES algorithm. The value of an encrypted field is only visible to users that have the “View Encrypted Data” permission. We do not recommend storing authentication data in encrypted custom fields, however these fields are suitable for storing other types of sensitive data (credit card information, social security numbers, etc).

Named Credentials

Named Credentials are a safe and secure way of storing authentication data for external services called from your apex code such as authentication tokens. We do not recommend storing other types of sensitive data in this field (such as credit card information). Be aware that users with customize application permission can view named credentials, so if your security policy requires that the secrets be hidden from subscribers, then please use a protected custom metadata type or protected custom setting. For more information, see named credentials in the online help and training guide.

General Guidance

When storing sensitive information on a machine:

  • All authentication secrets must be encrypted when stored on disk. This includes passwords, API Tokens, and OAuth Tokens.
  • For client apps running on a desktop, laptop, tablet, or mobile device, store all secrets in the vendor provided key store (keychain in OS X/iOS devices, keystore in Android devices, or in the registry protected with the DP-API on windows devices.) This is a hard requirement to pass the security review.
  • For services running on servers that must boot without user interaction, store secrets in a database encrypted with a key not available to the database process. The application layer should provide the key as needed to the database at runtime or should decrypt/encrypt as needed in its own process space.
  • Do not store any cryptographic keys used for protecting secrets in your application code
  • Be cautious of the algorithms and ciphers used in any cryptographic operations
  • Salt hashes, and if possible store salts and hashes separately
  • Leverage strong platform cryptographic solutions
  • Check if frameworks/platforms have already addressed the problem
  • Use SSL/TLS to transmit sensitive data

ASP.NET

ASP.NET provides access to the Windows CryptoAPIs and Data Protection API (DPAPI). This is intended to be used for the storage of sensitive information like passwords and encryption keys if the DataProtectionPermission has been granted to the code. Generally, the machine key is used to encrypt and decrypt sensitive data at the risk that if the machine is compromised malicious code could potentially decrypt any stored secrets. More information on this topic can be found here:

The strongest solution for ASP.NET would be to rely on a hardware solution for securely storing cryptographic keys, such as a cryptographic smartcard or Hardware Security Module (HSM), that is accessible by using the underlying Crypto API with a vendor supplied CryptoAPI Cryptographic Service Provider (CSP).

A .NET version of the bcrypt library called bcrypt.net is available.

Java

Java provides the KeyStore class for storing cryptographic keys. By default this uses a flat file on the server that is encrypted with a password. For this reason, an alternative Cryptographic Service Provider (CSP) is recommended. The strongest solution for Java would be to rely on a hardware solution for securely storing cryptographic keys, such as a cryptographic smartcard or Hardware Security Module (HSM), that is accessible by using the vendor's supplied CSP in that java.security configuration file. For more information on installing Java CSPs, consult the Java Cryptography Architecture (JCA) Reference Guide. When not using a CSP, if the product is a client application, you must use JAVA bindings to store the passphrase protecting the keystore in the vendor provided key store. Never store the passphrase in source code or in a property file. For server java solutions, follow the general guidance of making the passphrase protecting the keystore unavailable to the database process storing credentials.

A Java implementation of bcrypt is available called jBCrypt.

PHP

PHP does not provide cryptographically secure random number generators. Make sure to use /dev/urandom as the source for random numbers.

Use the mcrypt library for cryptography operations. Salted hashes and salts could be subsequently stored in a database.

A framework called phpass offers "OpenBSD-style Blowfish-based bcrypt" for PHP. For client apps, you must use native bindings to store user secrets in the vendor provided key store.

Ruby on Rails

There is a copy of bcrypt specifically for Ruby called bcrypt-ruby. For client apps, you must use ruby bindings to store secrets in the vendor provided key store.

Python

Use a module that interacts with the vendor provided keystores such as the python keyring module.

Flash/Air apps

Use the Encrypted Local Store which contains bindings to use vendor provided keystores to store secrets.