Non-encrypted confidential information
Need
Secure storage, transmission, and encryption of confidential information and credentials
Context
• Usage of Java 1.8 for developing applications
• Usage of Java 8 for developing applications with enhanced features and performance
• Usage of Java for building cross-platform applications
• Usage of java.io.* for input and output operations in Java
• Usage of javax.servlet.* for Java Servlet development
• Usage of javax.servlet.http.* for handling HTTP requests and responses in Java Servlets
• Usage of javax.servlet-api for developing Java Servlet applications
• Usage of mysql-connector-java for connecting to a MySQL database in Java
• Usage of javax.naming for accessing and manipulating naming and directory services in Java
• Usage of javax.naming.directory for accessing and manipulating directory services in Java
Description
1. Non compliant code
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class StoreServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {...**Plain-text credential storage and comparison.** In `StoreServlet`, the `doPost()` method retrieves the username and password from the request parameters and writes them directly to a file named `credentials.txt` in plain text using a `BufferedWriter`. In `LoginServlet`, the credentials used for authentication (`USERNAME` and `PASSWORD`) are hardcoded into the application's source code in plain text and compared directly against the submitted values. Anyone who gains access to the credentials file, the server file system, or the source code can read the usernames and passwords without any difficulty, and hardcoded credentials cannot be rotated without changing the source code and redeploying the application. **Credit card details sent and held in plain text.** `PaymentServlet` receives the credit card number, expiry date, and CVV from the request parameters and passes them straight to `processPayment` with no encryption. The details are sent as plain text (so a Man-in-the-Middle attacker can read them) and held as plain text in memory while the request is processed, violating PCI DSS, which requires that credit card details be encrypted in transit and at rest. **Plain-text password stored in the database over an unencrypted connection.** `UserServlet` opens a `DriverManager` connection to MySQL using hardcoded credentials (`"user"`/`"pass"`) and, in `doPost()`, inserts the submitted `username`/`password` into the database with the password stored in plain text. The connection to the database is not encrypted, so an attacker who intercepts the traffic can read everything sent to it, and the hardcoded database credentials are also exposed to anyone with access to the application code. **LDAP service credentials exposed in plain text.** `LDAPConnection` creates a connection to an LDAP server using `javax.naming.directory.InitialDirContext`, putting the security principal and credentials into the environment `Hashtable` in plain text: `env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=example,dc=com")` and `env.put(Context.SECURITY_CREDENTIALS, "password")`. Anyone with access to this code can see these credentials, risking unauthorized access to the LDAP service. **Password stored as reversible Base64 rather than encrypted.** `Base64LoginServlet` hardcodes a `USERNAME` and a `PASSWORD` that is only Base64-encoded (`"YWRtaW4="`), then compares the submitted password's Base64 encoding against it. Base64 is an encoding, not an encryption scheme — it is trivially reversible, so storing or comparing credentials this way offers no real confidentiality. **Hexadecimal-encoded data returned to the client without encryption.** `VulnerableServlet.doGet()` stores confidential information as a hexadecimal string (`"74657374696E67"`, i.e. `"testing"`) and writes it straight to the HTTP response. Hexadecimal is only an encoding, not encryption, so an attacker who intercepts the response can trivially decode it back to plain text.
2. Steps
• Use encryption to protect confidential information, and hashing for credentials used in authentication comparisons.
• Avoid storing or comparing sensitive information in plain text, and never hardcode credentials in the source code.
• Implement secure storage mechanisms such as hashing or encryption algorithms.
• Implement a secure authentication mechanism that does not rely on hard-coded credentials.
• Choose a strong encryption algorithm and generate a secure encryption key.
• Ensure that encryption keys and credentials are securely stored and managed (e.g., via environment variables or a secure configuration file), not hardcoded.
• Implement secure communication protocols (e.g., HTTPS, or SSL/TLS for LDAP) for transmitting sensitive data.
• Use a secure session management mechanism to store user information.
• Implement proper access controls to restrict unauthorized access to confidential or encrypted information.
• Implement input validation and parameterized queries to prevent SQL injection attacks.
• Follow PCI DSS standards and guidelines for handling and protecting credit card information.
• Regularly review and update credentials, including LDAP service credentials, to minimize the risk of unauthorized access.
• Regularly monitor and log database and application activities to detect unauthorized access or suspicious activities.
• Regularly backup the database and test the restoration process to ensure data integrity and availability.
• Follow best practices for secure coding and data handling, and regularly update and patch the software to address any security vulnerabilities.
3. Secure code example
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.security.*;
import java.nio.charset.StandardCharsets;...**`StoreServlet`/`LoginServlet`.** `StoreServlet` now encrypts the username and password with AES before writing them to the file, Base64-encoding the ciphertext (the key should be stored securely rather than hardcoded, as shown here for illustration). `LoginServlet` now compares a SHA-256 hash of the submitted password (via `MessageDigest`) against the stored hash rather than a plain-text value, so the original password can't be recovered from the stored copy. **`PaymentServlet`.** The card number, expiry, and CVV are now encrypted with AES (`Cipher`/`SecretKeySpec`) via the `encrypt` helper before being passed to `processPayment`. The application is assumed to run over HTTPS, use secure storage for the encrypted values, and enforce access controls and PCI DSS requirements around them. **`UserServlet`.** The password is now encrypted with AES before the `INSERT`, via a static `encrypt`/`generateKey` pair, and the result is Base64-encoded before being stored. Parameterized queries are already in use to avoid SQL injection; production deployments should also encrypt the database connection itself and manage the AES key outside of source code. **`LDAPConnection`.** The LDAP principal and credentials are now read from environment variables (`System.getenv("LDAP_PRINCIPAL")`/`System.getenv("LDAP_CREDENTIALS")`) instead of being hardcoded, keeping them out of the source code. Communication with the LDAP server should additionally be secured with SSL/TLS, and the credentials should be reviewed and rotated periodically. **`Base64LoginServlet`.** The password is now hashed with SHA-256 (via `hashPassword`, using `MessageDigest`) and the hash is Base64-encoded for comparison, rather than storing the password itself in reversible Base64. Credentials should still be moved out of the source code entirely in a real deployment, and HTTPS used for transport. **`SecureServlet`.** The confidential value is now encrypted with AES (`Cipher`/`SecretKeySpec`) via the `encrypt` helper before being written to the response, instead of being sent as a bare hexadecimal encoding. The key should be stored in a secure key vault rather than as a constant, and the endpoint should be served over HTTPS with proper access controls.
References
• 020. Non-encrypted confidential information