Introduction
Section titled “Introduction”CWE-539: Use of Persistent Cookies Containing Sensitive Information is a security vulnerability that involves the storage of sensitive data, such as Personally Identifiable Information (PII), in persistent cookies. These cookies, which are saved across sessions, can pose significant security risks if not handled properly. This article details the risks associated with PII exposure through CWE-539 and outlines remediation strategies, supported by coding examples in Java, JavaScript, and Python.
Understanding the Risks
Section titled “Understanding the Risks”Direct Risks
Section titled “Direct Risks”-
Unauthorized Access: Persistent cookies can be intercepted or accessed by unauthorized parties, especially if stored in plaintext.
-
Data Theft: If cookies containing PII are compromised, it can lead to identity theft and fraud.
-
Session Hijacking: Persistent cookies often store session information, which can be used for session hijacking if compromised.
Indirect Risks
Section titled “Indirect Risks”-
Reputational Damage: Breaches involving PII can damage an organization’s reputation, leading to a loss of customer trust and potential customer attrition.
-
Legal and Compliance Issues: Non-compliance with data protection laws (like GDPR and CCPA) due to improper handling of cookies can result in hefty fines and legal actions.
-
Operational Disruptions: Responding to and recovering from data breaches can consume significant resources and time.
Remediation Techniques
Section titled “Remediation Techniques”To mitigate the risks associated with storing sensitive information in persistent cookies, organizations should implement strategies like omitting sensitive data, masking data, and encrypting data before storage.
1. Omitting Data
Section titled “1. Omitting Data”Avoid storing sensitive or personally identifiable information in cookies altogether.
import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletResponse;
public class CookieManager { public void createSessionCookie(HttpServletResponse response, String sessionId) { Cookie sessionCookie = new Cookie("sessionID", sessionId); sessionCookie.setMaxAge(24 * 60 * 60); // Set for 24 hours response.addCookie(sessionCookie); // Ensure that no sensitive PII is stored in cookies }}// Express: HttpOnly cookies can only be set server-side, never via document.cookiefunction createSessionCookie(res, sessionId) { res.cookie('sessionID', sessionId, { httpOnly: true, secure: true, sameSite: 'strict', path: '/', maxAge: 86400000 }); // Do not store sensitive PII in cookies}from http.cookies import SimpleCookie
def create_session_cookie(session_id): cookie = SimpleCookie() cookie["sessionID"] = session_id cookie["sessionID"]["max-age"] = 86400 # Set for 24 hours cookie["sessionID"]["httponly"] = True print(cookie.output()) # Sensitive PII is not stored in the cookie2. Masking Data
Section titled “2. Masking Data”If any data must be stored in cookies and has potential privacy implications, it should be masked or anonymized.
import org.apache.commons.codec.digest.DigestUtils;
public class DataMasker { // PEPPER is loaded from your secret store, never hardcoded private static final String PEPPER = System.getenv("USER_ID_PEPPER");
public String maskUserId(String userId) { return "user-" + DigestUtils.sha256Hex(PEPPER + userId).substring(0, 12); }}const crypto = require('crypto');
// PEPPER is loaded from your secret store, never hardcodedconst PEPPER = process.env.USER_ID_PEPPER;
function maskUserId(userId) { return `user-${crypto.createHash('sha256').update(PEPPER + userId).digest('hex').slice(0, 12)}`;}import hashlibimport os
# PEPPER is loaded from your secret store, never hardcodedPEPPER = os.environ['USER_ID_PEPPER']
def mask_user_id(user_id): return 'user-' + hashlib.sha256((PEPPER + user_id).encode()).hexdigest()[:12]3. Encrypting Data
Section titled “3. Encrypting Data”Encrypt any sensitive information before storing it in a cookie to protect it from unauthorized access.
import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletResponse;import java.nio.ByteBuffer;import java.nio.charset.StandardCharsets;import java.security.SecureRandom;
public class EncryptionUtility { // key is supplied by the caller, sourced from your KMS or secret store public static void encryptAndAddCookie(HttpServletResponse response, String data, SecretKey key) throws Exception { byte[] iv = new byte[12]; new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv)); byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
byte[] payload = ByteBuffer.allocate(iv.length + encryptedData.length).put(iv).put(encryptedData).array(); String encryptedString = java.util.Base64.getEncoder().encodeToString(payload);
Cookie secureCookie = new Cookie("secureData", encryptedString); secureCookie.setHttpOnly(true); secureCookie.setMaxAge(24 * 60 * 60); response.addCookie(secureCookie); }}const crypto = require('crypto');
// Express: the cookie is set server-side so HttpOnly is actually honored// key: 32-byte Buffer loaded from your KMS or secret storefunction encryptAndAddCookie(res, data, key) { const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); const encrypted = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]); const value = iv.toString('hex') + ':' + encrypted.toString('hex'); res.cookie('secureData', value, { httpOnly: true, secure: true, sameSite: 'strict', path: '/', maxAge: 86400000 });}from cryptography.fernet import Fernetfrom http.cookies import SimpleCookie
# key: Fernet key loaded from your secret store, never generated per calldef encrypt_and_add_cookie(data, key): cipher_suite = Fernet(key) encrypted_data = cipher_suite.encrypt(data.encode())
cookie = SimpleCookie() cookie["secureData"] = encrypted_data.decode() cookie["secureData"]["max-age"] = 86400 cookie["secureData"]["httponly"] = True print(cookie.output())Conclusion
Section titled “Conclusion”Mitigating the risks associated with CWE-539 is essential for protecting PII and maintaining the security of web applications. By implementing effective cookie management strategies such as omitting sensitive data, masking, and encrypting information, organizations can enhance their compliance with privacy regulations and secure the data of their users.
