Security Best Practices for Developers

Master essential security practices for modern application development. Learn how to implement secure authentication, manage passwords safely, verify data integrity, and protect sensitive information.

Overview

Security is not optional in modern software development. This guide covers fundamental security practices every developer should follow: secure authentication with JWT, strong password generation, data integrity verification with hashing and HMAC, and secure credential management.

Estimated time: 30-40 minutes

Prerequisites: Basic understanding of web security concepts and cryptography

Step 1: Implement Secure Authentication with JWT

JSON Web Tokens (JWT) provide a stateless authentication mechanism for modern applications. Proper implementation is critical for security.

🔒 Security Principle: Token-Based Authentication

JWTs contain encoded claims that can be verified without database lookups. However, they must be properly signed and validated to prevent tampering.

Secure JWT Payload Structure

{
  "sub": "user_12345",           // Subject: User identifier
  "email": "user@example.com",   // User email
  "role": "user",                // Authorization role
  "iat": 1704067200,             // Issued at (Unix timestamp)
  "exp": 1704153600,             // Expiration (24 hours later)
  "iss": "https://api.example.com", // Issuer
  "aud": "https://app.example.com"  // Audience
}

Use the JWT Generator to create tokens with proper claims. Always include expiration (exp) and issued-at (iat) claims to limit token lifetime.

JWT Best Practices

  • Use RS256 for production: Asymmetric signing prevents token forgery
  • Set short expiration times: 15 minutes for access tokens, longer for refresh tokens
  • Include audience and issuer: Prevent token reuse across services
  • Never store sensitive data: JWTs are encoded, not encrypted
  • Validate on every request: Check signature, expiration, and claims
  • Implement token refresh: Use refresh tokens to issue new access tokens

Algorithm Selection Guide

// Development/Testing: HS256 (Symmetric)
// - Simple secret key
// - Fast signing and verification
// - Secret must be shared with all services

// Production: RS256 (Asymmetric)
// - Private key for signing (kept secret)
// - Public key for verification (can be shared)
// - Better security for distributed systems
// - Prevents token forgery even if public key is known

Use the JWT Decoder to inspect tokens during development and debugging. Remember: decoding is not verification - always validate signatures in production.

Step 2: Generate Strong Passwords

Weak passwords are the #1 cause of account compromises. Generate cryptographically secure passwords for users, API keys, and service accounts.

🔒 Security Principle: Password Strength

Strong passwords use high entropy (randomness) and sufficient length to resist brute-force attacks. A 16-character password with mixed character types provides ~95 bits of entropy.

Password Strength Guidelines

// Weak: 8 characters, lowercase only
// Entropy: ~37 bits (crackable in seconds)
password

// Medium: 12 characters, mixed case + numbers
// Entropy: ~71 bits (crackable in days/weeks)
MyPass123456

// Strong: 16+ characters, all character types
// Entropy: ~95 bits (crackable in centuries)
K9$mP2#vL8@nQ4!x

// Very Strong: 20+ characters, all types
// Entropy: ~119 bits (practically uncrackable)
T7&kR3$mN9@pL2#vQ5!x

Use the Password Generator to create secure passwords. Configure length (minimum 16 characters) and enable all character types for maximum security.

Password Management Best Practices

  • Minimum 12 characters: 16+ recommended for sensitive accounts
  • Use all character types: Uppercase, lowercase, numbers, symbols
  • Avoid patterns: No dictionary words, dates, or sequential characters
  • Unique per service: Never reuse passwords across accounts
  • Use a password manager: Store passwords securely, not in plain text
  • Implement password policies: Enforce minimum requirements in your apps
  • Hash passwords properly: Use bcrypt, Argon2, or PBKDF2 (never MD5 or SHA-1)
⚠️ Warning: Never store passwords in plain text, even in development. Always hash passwords before storing them in databases. Use bcrypt with a cost factor of at least 10 for production systems.

Step 3: Verify Data Integrity with Hashing

Cryptographic hashes ensure data hasn't been tampered with during transmission or storage. Use them for file integrity verification and data fingerprinting.

🔒 Security Principle: Cryptographic Hashing

Hash functions produce fixed-size outputs from variable-size inputs. Any change to the input produces a completely different hash, making tampering detectable.

Hash Algorithm Selection

// ❌ Avoid: MD5 and SHA-1 (Broken)
// - Collision attacks possible
// - Not suitable for security purposes
// - Only use for non-security checksums

// ✅ Use: SHA-256 (Recommended)
// - 256-bit output
// - No known practical attacks
// - Good balance of security and speed
// - Widely supported

// ✅ Use: SHA-384 or SHA-512 (High Security)
// - Larger output sizes
// - Higher security margin
// - Slightly slower than SHA-256
// - Use for highly sensitive data

Use the Hash Generator for text hashing and the File Checksum Calculator for file integrity verification. Both tools use the Web Crypto API for secure computation.

Common Hashing Use Cases

  • File integrity: Verify downloads haven't been corrupted or tampered with
  • Data deduplication: Identify duplicate files or content
  • Digital signatures: Hash data before signing for efficiency
  • Blockchain: Link blocks together with hash chains
  • Cache keys: Generate unique identifiers for cached content

Example: Verifying File Integrity

// 1. Publisher provides file and hash
file: application-v1.0.0.zip
SHA-256: a3c5f8d2e9b1c4a7f6e3d8b2c9a1f4e7d3b6c8a2f5e9d1c4b7a3f6e2d8c5b1a4

// 2. Download the file
// 3. Calculate hash using File Checksum Calculator
// 4. Compare hashes

// ✅ Hashes match: File is authentic and unmodified
// ❌ Hashes differ: File is corrupted or tampered with

Step 4: Implement Message Authentication with HMAC

HMAC (Hash-based Message Authentication Code) provides both data integrity and authenticity verification. Use it for API request signing and webhook validation.

🔒 Security Principle: Message Authentication

HMAC combines a secret key with a hash function to create a signature that proves both the message's integrity and the sender's identity. Only parties with the secret key can generate valid signatures.

HMAC Workflow

// Sender (API Client)
1. Prepare message: "user_id=123&action=update"
2. Generate HMAC: HMAC-SHA256(message, secret_key)
3. Send message + HMAC signature

// Receiver (API Server)
1. Receive message + signature
2. Calculate HMAC: HMAC-SHA256(message, secret_key)
3. Compare calculated HMAC with received signature
4. ✅ Match: Message is authentic and unmodified
   ❌ Mismatch: Message is invalid or tampered with

Use the HMAC Generator to create and verify HMAC signatures. Supports SHA-256, SHA-384, and SHA-512 algorithms with hex and base64 output formats.

HMAC Best Practices

  • Use SHA-256 or higher: Avoid SHA-1 and MD5
  • Keep secrets secure: Never expose HMAC keys in client-side code
  • Use constant-time comparison: Prevent timing attacks when verifying
  • Include timestamps: Prevent replay attacks by adding expiration
  • Rotate keys periodically: Limit exposure if keys are compromised
  • Use different keys per purpose: Separate keys for different services

Example: Webhook Signature Verification

// Webhook payload
{
  "event": "user.created",
  "user_id": 12345,
  "timestamp": 1704067200
}

// Provider sends:
// X-Webhook-Signature: sha256=a3c5f8d2e9b1c4a7f6e3d8b2c9a1f4e7...

// Your verification:
1. Get webhook secret from environment
2. Calculate HMAC-SHA256(payload, secret)
3. Compare with X-Webhook-Signature header
4. Only process if signatures match

Step 5: Secure Credential Management

Proper credential management prevents unauthorized access and data breaches. Never hardcode secrets in source code or commit them to version control.

🔒 Security Principle: Secrets Management

Credentials should be stored separately from code, encrypted at rest, and accessed only by authorized services. Use environment variables, secret managers, or vaults.

Credential Storage Best Practices

  • Use environment variables: Store secrets outside source code
  • Never commit secrets: Add .env files to .gitignore
  • Use secret managers: AWS Secrets Manager, HashiCorp Vault, Azure Key Vault
  • Rotate credentials regularly: Change passwords and keys periodically
  • Limit access scope: Grant minimum necessary permissions
  • Encrypt at rest: Use encryption for stored credentials
  • Audit access: Log who accesses secrets and when
  • Use different credentials per environment: Separate dev, staging, production

Environment Variable Management

# .env.example (commit this)
DATABASE_URL=postgresql://localhost:5432/myapp
JWT_SECRET=your-secret-here
API_KEY=your-api-key-here

# .env (DO NOT commit this)
DATABASE_URL=postgresql://prod-db:5432/myapp
JWT_SECRET=K9$mP2#vL8@nQ4!xT7&kR3$m
API_KEY=sk_live_abc123def456ghi789

# .gitignore
.env
.env.local
.env.*.local

Use the Environment File Formatter to validate and format .env files. It detects duplicate keys and validates variable names.

⚠️ Warning: If you accidentally commit secrets to Git, consider them compromised. Rotate the credentials immediately and use tools like git-secrets or truffleHog to prevent future leaks.

Step 6: Implement Defense in Depth

Security is not a single solution but layers of protection. Implement multiple security controls so that if one fails, others still protect your system.

Security Layers

1. Authentication Layer

Verify user identity with JWT, OAuth2, or multi-factor authentication

2. Authorization Layer

Control access with role-based or attribute-based access control

3. Transport Layer

Encrypt data in transit with TLS/HTTPS (minimum TLS 1.2)

4. Data Layer

Encrypt sensitive data at rest, hash passwords with bcrypt/Argon2

5. Application Layer

Validate input, sanitize output, prevent injection attacks

6. Monitoring Layer

Log security events, detect anomalies, alert on suspicious activity

Security Checklist

Authentication & Authorization

  • ✓ Use JWT with RS256 for production
  • ✓ Set short token expiration times
  • ✓ Implement token refresh mechanism
  • ✓ Validate tokens on every request
  • ✓ Use HTTPS for all authentication endpoints

Password Security

  • ✓ Enforce minimum 12-character passwords
  • ✓ Require mixed character types
  • ✓ Hash passwords with bcrypt (cost ≥10)
  • ✓ Never store passwords in plain text
  • ✓ Implement account lockout after failed attempts

Data Integrity

  • ✓ Use SHA-256 or higher for hashing
  • ✓ Verify file checksums before processing
  • ✓ Implement HMAC for API request signing
  • ✓ Validate webhook signatures
  • ✓ Use constant-time comparison for signatures

Secrets Management

  • ✓ Store secrets in environment variables
  • ✓ Never commit secrets to version control
  • ✓ Use secret managers for production
  • ✓ Rotate credentials regularly
  • ✓ Audit secret access

Related Tools

Frequently Asked Questions

Should I use HS256 or RS256 for JWT?

Use HS256 (symmetric) for development and single-service architectures where the secret can be kept secure. Use RS256 (asymmetric) for production and microservices where multiple services need to verify tokens but shouldn't be able to create them.

How long should JWT tokens be valid?

Access tokens: 15 minutes to 1 hour. Refresh tokens: 7-30 days. Shorter lifetimes are more secure but require more frequent refreshes. Balance security with user experience based on your application's sensitivity.

What's the difference between hashing and encryption?

Hashing is one-way (cannot be reversed) and used for integrity verification and password storage. Encryption is two-way (can be decrypted) and used for confidentiality. Use hashing for passwords, encryption for sensitive data that needs to be retrieved.

Why use HMAC instead of just hashing?

Plain hashing only verifies integrity, not authenticity. Anyone can calculate a hash. HMAC requires a secret key, so only parties with the key can generate valid signatures. This proves both integrity and authenticity.

How do I securely store API keys in my application?

Use environment variables for local development, secret managers (AWS Secrets Manager, Azure Key Vault) for production. Never hardcode keys in source code or commit them to Git. Rotate keys regularly and use different keys per environment.

What should I do if I accidentally commit a secret to Git?

1) Immediately rotate the compromised credential. 2) Remove the secret from Git history using git-filter-branch or BFG Repo-Cleaner. 3) Force push the cleaned history. 4) Notify your team. 5) Implement pre-commit hooks to prevent future leaks.