Non-encrypted confidential information
Need
Secure storage, transmission, and encryption of confidential information and credentials
Context
• Usage of TypeScript for statically typed JavaScript development
• Usage of Node.js v14.0.0 for server-side JavaScript development
• Usage of Express for building web applications and handling HTTP requests and APIs
• Usage of body-parser for parsing request bodies in Express
• Usage of fs for file system operations
• Usage of ldapjs for LDAP (Lightweight Directory Access Protocol) operations
• Usage of base-64 for encoding and decoding data in base64 format
Description
1. Non compliant code
import express from 'express';
import bodyParser from 'body-parser';
import fs from 'fs';
import ldap from 'ldapjs';
import * as base64 from 'base-64';
const app = express();
app.use(bodyParser.json());...**Confidential data stored in a file without encryption.** User queries are appended to a plain text file (`queries.txt`) with no encryption. Anyone with access to the file system can read its contents directly. **LDAP service credentials exposed in plain text.** The `bindDN` and `bindCredentials` used to authenticate against the LDAP service are built directly from unprotected request query parameters and used as-is, with no encryption at any point. **Credit card information handled without encryption.** The credit card number, CVV, and expiration date are read from the request body and used to process a payment without ever being encrypted, in transit or at rest. **Credentials stored in plain text in the source code.** A password is hard-coded (`'secretpassword'`) directly in the source and compared to user input with a plain equality check. **Credentials encoded (not encrypted) with Base64.** A hard-coded username and password are combined and passed through `base64.encode()`. Base64 is a reversible encoding, not encryption, so it provides no real protection. **Confidential information encoded (not encrypted) in hexadecimal.** A confidential string is stored as a hexadecimal literal and decoded with `Buffer.from(..., 'hex')`. As with Base64, this only obfuscates the data and is trivially reversible.
2. Steps
• Remove any hard-coded, plain text, Base64-"encoded", or hexadecimal-"encoded" confidential information and credentials from the source code.
• Install and import a suitable encryption/hashing library (e.g. bcrypt for passwords, crypto or a dedicated encryption library for other confidential data).
• Generate a secret key, salt, or passphrase to use for encryption, and store it securely rather than hard-coding it.
• Encrypt or hash the sensitive information before storing or transmitting it, using bcrypt for passwords/credentials and strong encryption (e.g. AES-256) for other confidential data.
• Update the code to use the encrypted or hashed data instead of the plain text, Base64, or hexadecimal value.
• Decrypt the data only when strictly necessary, and never log or otherwise expose the decrypted value.
• Store LDAP and other service credentials in a secure configuration file or environment variables rather than in the source code or request parameters.
• Consider using a secure tokenization solution for highly sensitive data such as credit card numbers.
• Ensure sensitive information, API keys, and passwords are not included in the source code or committed to version control systems.
• Regularly review and update encryption and credential-handling practices to align with industry standards and best practices.
3. Secure code example
import express from 'express';
import bodyParser from 'body-parser';
import fs from 'fs';
import bcrypt from 'bcrypt';
import ldap from 'ldapjs';
import { decryptCredentials } from './encryptionUtils';
import { encrypt } from 'encryption-library'; // Replace with the actual encryption library you are using
import crypto from 'crypto';...**Confidential data.** The query is hashed with bcrypt before being appended to `queries.txt`, and read access compares the stored hash with the incoming value using `bcrypt.compare()` rather than storing or reading plain text. **LDAP service credentials.** The password only ever exists in encrypted form outside the request handler; `decryptCredentials()` decrypts it in memory immediately before it's used to bind to the LDAP client, so it is never stored or logged in plain text. **Credit card information.** The credit card number, CVV, and expiration date are encrypted (via the `encrypt` function from a chosen encryption library) before being used to process the payment, so the sensitive values are never handled in plain text. **Credentials.** Instead of a hard-coded plain text password, a bcrypt hash is stored and compared against user input using `bcrypt.compare()`, so the real password is never present in the source code. **Credentials.** Instead of Base64-"encoding" the credentials, the password is hashed with `bcrypt.hash()` before being used, since Base64 was never providing real protection. **Confidential information.** Instead of hexadecimal encoding, the data is encrypted with AES-256-CBC (Node's `crypto` module) using a secret key that should be stored securely (e.g. in a secrets manager) rather than hard-coded, and is only decrypted when needed.
References
• 020. Non-encrypted confidential information