DEV Community

Cover image for Solved: What’s the best practice to encrypt password?
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: What’s the best practice to encrypt password?

🚀 Executive Summary

TL;DR: The article addresses the misconception of ‘encrypting’ passwords, advocating instead for secure hashing with Key Derivation Functions (KDFs) like Argon2 for user credentials. It also details the use of Hardware Security Modules (HSMs) for master key protection and centralized Vault systems for managing application secrets, ensuring robust security throughout the credential lifecycle.

🎯 Key Takeaways

  • User passwords should never be encrypted but securely hashed using computationally expensive Key Derivation Functions (KDFs) such as Argon2, bcrypt, or scrypt, combined with unique salts to prevent rainbow table and brute-force attacks.
  • Master encryption keys, digital certificates, and other critical secrets require the highest level of protection, best achieved through Hardware Security Modules (HSMs) or Trusted Platform Modules (TPMs), or cloud-based Key Management Systems (KMS) backed by HSMs.
  • Application secrets like API keys and database credentials should be managed centrally using Secure Credential Management Systems (Vaults) that offer dynamic secret generation, granular access control, comprehensive audit trails, and automated rotation.

This post demystifies secure password storage, moving beyond simple encryption to explain best practices for hashing user credentials and protecting application secrets. Learn about Key Derivation Functions, Hardware Security Modules, and centralized vault solutions for robust security.

Understanding the Challenge: Symptoms of Insecure Password Practices

The seemingly straightforward question “What’s the best practice to encrypt password?” often masks a deeper set of challenges and misconceptions within IT environments. Many organizations inadvertently adopt practices that create significant security vulnerabilities. Recognizing these symptoms is the first step towards robust security:

  • Storing Plaintext Passwords: The most egregious error. Any breach instantly exposes all user credentials. This extends to hardcoding API keys or database credentials directly into application source code or configuration files.
  • Using Weak Hashing Algorithms: Employing fast, non-salted hashing functions like MD5 or SHA-1 for user passwords is a critical flaw. While they produce a “hash,” their speed makes them vulnerable to rainbow table attacks and brute-force guessing using powerful hardware (GPUs).
  • Simple Symmetric Encryption Without Key Management: Encrypting sensitive data (like database connection strings or API keys) with a static key stored alongside the encrypted data offers minimal protection. If the key is compromised, all encrypted data is immediately exposed.
  • Lack of Centralized Secret Management: Spreading secrets across multiple servers, configuration files, and developer workstations creates a sprawling attack surface, makes auditing impossible, and hinders rotation.
  • Poor Access Control: Without granular control over who can access which secret, you risk insider threats or excessive privileges for automated systems.
  • Absence of Auditing and Rotation: Inability to track who accessed a secret and when, or difficulty in rotating credentials regularly, compromises accountability and increases the window of exposure for compromised secrets.

The goal isn’t just to “encrypt” but to protect credentials throughout their lifecycle, ensuring confidentiality, integrity, and availability only to authorized entities.

Solution 1: Secure Hashing with Salting and Key Derivation Functions (KDFs) for User Passwords

For user passwords, the best practice is not to encrypt them, but to hash them securely. You should never be able to decrypt a user’s password back to its original form. Instead, you store a hash, and when a user attempts to log in, you hash their provided password and compare it to the stored hash.

Why Traditional Hashing is Insufficient

Standard cryptographic hash functions like SHA-256 are designed for speed. This is great for data integrity checks but disastrous for passwords, as it makes brute-force attacks extremely efficient.

The Role of Salting

A salt is a unique, random string added to each password *before* hashing. Its primary purpose is to prevent rainbow table attacks, where pre-computed hashes are used to quickly find matching passwords. A unique salt for every password ensures that even if two users have the same password, their stored hashes will be completely different.

The Power of Key Derivation Functions (KDFs)

KDFs are purpose-built hashing algorithms designed to be computationally expensive and slow, making brute-force guessing impractical. They achieve this by performing many iterations of a hashing process and often requiring significant memory. Key KDFs include:

  • PBKDF2 (Password-Based Key Derivation Function 2): A widely used KDF, specified in RFC 2898. It applies a pseudorandom function (like HMAC) repeatedly to derive a key from a password.
  • bcrypt: Based on the Blowfish cipher, bcrypt is specifically designed to be slow and adaptive (its cost factor can be increased over time as computational power grows).
  • scrypt: Offers a memory-hard function, meaning it requires significant amounts of RAM, making it harder to parallelize attacks on GPUs.
  • Argon2: The winner of the Password Hashing Competition (PHC) in 2015, Argon2 is generally considered the strongest and most flexible KDF today. It’s configurable for memory, time, and parallelism, resisting both GPU and custom hardware attacks.

Example: Python with passlib and Argon2

Using a library like passlib in Python simplifies the implementation of strong KDFs.

from passlib.context import CryptContext

# Configure Argon2id as the default password hashing scheme.
# 'argon2' specifies Argon2id, the recommended variant.
# 'deprecated="auto"' automatically upgrades old hashes if verified.
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")

def hash_password(password: str) -> str:
    """Hashes a plaintext password using Argon2."""
    return pwd_context.hash(password)

def verify_password(password: str, hashed_password: str) -> bool:
    """Verifies a plaintext password against a stored hash."""
    try:
        return pwd_context.verify(password, hashed_password)
    except Exception:
        # Handle cases where the hash is malformed or an invalid scheme
        return False

# --- Example Usage ---
user_password = "MyStrongPassword!123"
hashed_pwd = hash_password(user_password)
print(f"Original Password: {user_password}")
print(f"Hashed Password: {hashed_pwd}")

# Verification attempts
print(f"Verification (correct password): {verify_password(user_password, hashed_pwd)}")
print(f"Verification (incorrect password): {verify_password('WrongPassword!123', hashed_pwd)}")
print(f"Verification (tampered hash - expected False): {verify_password(user_password, hashed_pwd[:-5] + 'AAAAA')}")
Enter fullscreen mode Exit fullscreen mode

Example: Generating a SHA512-crypt Hash on Linux

For system user passwords (e.g., in /etc/shadow), Linux distributions commonly use SHA512-crypt, which is an iterative hashing scheme with salting. While not as strong as Argon2, it’s a significant improvement over older methods.

# Generate a SHA512-crypt hash for 'mySystemPassword'.
# The 'mkpasswd' utility from the 'whois' package is often used.
# If 'mkpasswd' is not available, 'openssl passwd -6' can be used.
mkpasswd -m sha-512 "mySystemPassword"
# Example output: $6$randomsaltstring$A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z (a very long hash)
Enter fullscreen mode Exit fullscreen mode

This generated hash is then typically stored in /etc/shadow along with the username, replacing previous hash entries.

Solution 2: Hardware Security Modules (HSMs) and Trusted Platform Modules (TPMs) for Key Protection

While KDFs are for user passwords, organizations often have other “passwords” or secrets: API keys, database connection strings, digital certificates, master encryption keys. For these critical secrets, especially the master keys that encrypt other secrets, Hardware Security Modules (HSMs) and Trusted Platform Modules (TPMs) offer the highest level of protection.

Hardware Security Modules (HSMs)

HSMs are physical computing devices that safeguard and manage digital keys, perform cryptographic operations, and provide tamper detection and resistance. They are designed to meet stringent security standards (e.g., FIPS 140-2 compliance).

  • Key Generation and Storage: Keys are generated and stored within the HSM and often cannot be exported, meaning they never leave the secure hardware boundary.
  • Cryptographic Operations: Encryption, decryption, signing, and verification operations happen inside the HSM, preventing key exposure even during use.
  • Tamper Resistance: HSMs are built to detect and react to physical tampering attempts, often zeroing out keys if such an attempt is detected.
  • Audit Trails: Provide detailed logs of all key usage.

HSMs are ideal for protecting root Certificate Authority (CA) keys, master keys for Key Management Systems (KMS), payment processing keys, and high-value application secrets.

Trusted Platform Modules (TPMs)

TPMs are microcontrollers that store cryptographic keys, passwords, and digital certificates to secure hardware. They are typically integrated into server motherboards, PCs, and laptops.

  • Platform Integrity: TPMs can verify the integrity of a system’s boot process, ensuring that no malicious software has tampered with it.
  • Disk Encryption: Often used to secure disk encryption keys (e.g., BitLocker on Windows), ensuring that the disk can only be decrypted on the authorized machine.
  • Secure Key Storage: While less robust than a dedicated HSM, TPMs provide a secure environment for storing sensitive keys tied to a specific device.

Cloud-based Key Management Systems (KMS)

For cloud environments, major providers offer managed KMS solutions backed by HSMs, providing enterprise-grade key management without the operational overhead of managing physical hardware.

  • AWS Key Management Service (KMS): Uses FIPS 140-2 validated HSMs to protect encryption keys. Users can create, store, and control access to Customer Master Keys (CMKs) which can then be used to encrypt data within various AWS services or directly by applications.
  # Example: Encrypting plaintext using an AWS KMS Customer Master Key (CMK)
  # The actual encryption operation happens within the KMS HSM.
  # The 'fileb://' prefix means read from a binary file.
  aws kms encrypt --key-id alias/MyApplicationKey --plaintext fileb://<(echo "My super secret data") --query CiphertextBlob --output text
  # Output: AQIDAHh+... (Base64 encoded ciphertext)

  # Example: Decrypting the ciphertext
  aws kms decrypt --ciphertext-blob fileb://<(echo "AQIDAHh+..." | base64 --decode) --query Plaintext --output text | base64 --decode
  # Output: My super secret data
Enter fullscreen mode Exit fullscreen mode
  • Azure Key Vault: A centralized cloud service for managing keys, secrets, and certificates. It can be used to securely store and control access to tokens, passwords, certificates, API keys, and other secrets.
  • Google Cloud KMS: Offers similar capabilities, allowing users to manage cryptographic keys in a cloud-hosted solution. Keys can be software-backed or HSM-backed.

Solution 3: Secure Credential Management Systems (Vaults) for Application Secrets

While KDFs handle user passwords and HSMs protect master keys, application secrets (database credentials, API keys, service accounts, SSH keys, certificates) require a comprehensive system. Secure Credential Management Systems, often referred to as “Vaults,” provide centralized, dynamic, and policy-driven management for these secrets.

Key Benefits of a Vault System

  • Centralized Storage: All secrets are stored in one location, encrypted at rest.
  • Dynamic Secrets: Generate unique, short-lived credentials on demand (e.g., a database user created just for a specific application instance, expiring after an hour).
  • Access Control: Granular, policy-based access control tied to identity (human users, machines, applications).
  • Audit Trails: Comprehensive logging of all secret access, creation, and revocation.
  • Secret Rotation: Facilitate automated rotation of secrets to minimize risk.
  • Encryption as a Service: Many vaults can perform encryption/decryption without exposing the underlying keys to applications.

Example: HashiCorp Vault

HashiCorp Vault is a leading open-source secret management tool. It protects secrets by sealing itself on startup and requiring “unseal keys” (often using Shamir’s Secret Sharing) to decrypt its master encryption key.

Conceptual Vault Workflow

  1. Initialization & Unseal: Vault starts in a sealed state. Operators use their shares of the unseal key to bring it online.
  2. Authentication: Applications or users authenticate to Vault using various methods (e.g., AWS IAM, Kubernetes service accounts, AppRole, LDAP).
  3. Policy Enforcement: Based on the authenticated identity, Vault applies policies to determine what secrets the entity can access.
  4. Secret Retrieval: The application requests a secret. Vault either provides a static secret or dynamically generates a new, temporary one.

Example: Basic HashiCorp Vault Interaction (CLI)

# Assume Vault is running and unsealed, and you're authenticated (e.g., via 'vault login').

# 1. Enable a Key-Value (KV) secrets engine (version 2 for data versioning)
vault secrets enable -version=2 kv

# 2. Write a secret (e.g., an API key for a service)
vault kv put kv/production/myapp/api-key client_id="xyz123" client_secret="super-secret-key-123"

# 3. Read a secret
vault kv get kv/production/myapp/api-key
# Expected output will show the secret data:
# ====== Secret Path: kv/production/myapp/api-key ======
# Data
# ----
# client_id:      xyz123
# client_secret:  super-secret-key-123

# 4. Configure a policy to allow an application to read this secret
# (This would be written to a file, then applied to Vault)
# Path: myapp-read-policy.hcl
# path "kv/data/production/myapp/api-key" {
#   capabilities = ["read"]
# }
# vault policy write myapp-reader myapp-read-policy.hcl

# 5. An application using an AppRole or Kubernetes auth could then get a token
# with 'myapp-reader' policy and retrieve the secret.
Enter fullscreen mode Exit fullscreen mode

Example: ansible-vault for Configuration Management Secrets

For infrastructure-as-code tools like Ansible, ansible-vault provides a simple way to encrypt sensitive data (e.g., database passwords, API keys) directly within your playbooks and roles. It’s suitable for secrets that are relatively static and needed at deployment time, rather than dynamic, runtime secrets.

# Create a new encrypted YAML file to store secrets
ansible-vault create group_vars/all/vault_secrets.yml
# This will prompt you to set a password for the vault file.
# You then enter your secrets:
# ---
# db_password: "MySuperSecureDBPassword"
# api_key_service_a: "a_long_api_key_for_service_a"

# Edit an existing encrypted vault file
ansible-vault edit group_vars/all/vault_secrets.yml

# View an encrypted vault file (without editing)
ansible-vault view group_vars/all/vault_secrets.yml

# To use these secrets in an Ansible playbook:
# When running the playbook, you'll need to provide the vault password:
# ansible-playbook my_playbook.yml --ask-vault-pass
# Or, use a vault password file:
# ansible-playbook my_playbook.yml --vault-password-file ~/.ansible/vault_pass.txt
Enter fullscreen mode Exit fullscreen mode

Secrets stored in vault\_secrets.yml can then be referenced in your playbooks like any other variable (e.g., {{ db\_password }}).

Comparison of Password & Secret Management Solutions

Understanding when to use each approach is crucial for building a comprehensive security posture.

Feature / Solution KDFs (e.g., Argon2, bcrypt) HSMs / TPMs Credential Management Systems (Vaults)
Primary Use Case Securely hashing and storing user passwords for authentication. Protecting master encryption keys, digital certificates, and performing secure cryptographic operations. Centralized management of application secrets (API keys, DB creds, certificates) and dynamic secret generation.
Data Stored Password hashes (original passwords are not recoverable). Cryptographic keys and certificates (often non-exportable). Various secrets: API keys, DB credentials, tokens, SSH keys, certificates.
Security Mechanism Computationally expensive hashing, unique salting per password, memory-hard functions. Hardware-based tamper resistance, secure key generation/storage, FIPS compliance, isolation. Encrypted at-rest and in-transit, robust access control policies, audit logging, dynamic secret generation.
Complexity Relatively simple library integration into authentication logic. Requires specialized hardware or integration with cloud KMS services; significant operational overhead for on-premise HSMs. Significant setup and operational overhead; requires dedicated infrastructure or managed service; complex policy configuration.
Cost Low (software libraries are free). High (dedicated hardware units can be very expensive); Moderate (cloud KMS services are usage-based). Moderate to High (infrastructure costs, licensing for enterprise features, operational staff).
Best For Any system requiring user authentication (web applications, APIs, operating systems). High-security key storage for critical infrastructure components, root CAs, critical data encryption. Managing secrets for microservices, CI/CD pipelines, cloud-native applications, and complex IT environments.

Darian Vance

👉 Read the original article on TechResolve.blog

Top comments (0)