Security Best Practices: Hashing, Salts, and Secrets

Security Best Practices: Hashing, Salts, and Secrets

Protect your data. Learn the essential security patterns for handling passwords, managing secrets, and securing your FastAPI code against common vulnerabilities.

Security Best Practices: Hashing, Salts, and Secrets

Security is not a feature you "Add" at the end; it is a foundation you build upon. A single data breach can destroy a company's reputation and financial stability.

In this lesson, we learn how to protect the most sensitive part of our system: the User's identity and secrets.


1. Password Hashing (Never store raw text!)

You must never store a user's password as plain text in your database. If an attacker gains access to your database, they immediately have every user's credentials.

The Solution: One-way Hashing

We use algorithms like Bcrypt or Argon2.

  • Hashing: A function that turns a password into a scrambled string that cannot be reversed.
  • Salting: Adding a unique, random string to every password before hashing it. This prevents "Rainbow Table" attacks (where attackers pre-calculate hashes for common passwords).
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def get_password_hash(password):
    return pwd_context.hash(password)

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

2. Secrets Management

Your API likely needs a SECRET_KEY for JWTs and an API_KEY for services like Stripe.

  • Rule #1: Never hard-code secrets in your Python files.
  • Rule #2: Never commit secrets to Git.

The Solution: Environment Variables

Use .env files locally and "Secret Managers" (like AWS Secrets Manager or Vault) in production. Pydantic's BaseSettings makes this effortless.

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    secret_key: str
    database_url: str

    class Config:
        env_file = ".env"

settings = Settings()

3. Rate Limiting

Even a secure API can be taken down by a Brute Force attack (trying 1,000 passwords a second).

  • Rate Limiting is the process of limiting how many requests a single IP address can make in a certain timeframe.
  • Tool: slowapi is a popular library for adding rate limiting to FastAPI.

4. SQL Injection and XSS

FastAPI protects you from many common web attacks by default:

  • SQL Injection: Using SQLModel/SQLAlchemy automatically "Escapes" data so attackers can't run malicious SQL.
  • XSS: FastAPI's automatic JSON serialization prevents many types of script injection attacks.

Visualizing Password Verification

graph TD
    A["User enters 'mypassword123'"] --> B["API receives plain text"]
    B --> C["Fetch Hash from DB: '$2b$12$...'"]
    C --> D["Bcrypt: Hash('mypassword123') matches Hash from DB?"]
    D -- "Yes" --> E["Login Success"]
    D -- "No" --> F["Login Fail (401)"]

Summary

  • Bcrypt: Use it for all password storage.
  • Environment Variables: The ONLY place for keys and secrets.
  • Rate Limiting: Essential to prevent brute-force and DDoS attacks.
  • Framework Defaults: FastAPI + Pydantic + SQLModel provides a "Secure by Default" experience.

In the next lesson, we’ll look at Input Sanitization and Resource Protection.


Exercise: The Secret Leak

You accidentally committed your .env file to a public GitHub repository.

  1. Is it enough to just delete the file from the repo and commit again?
  2. What are the three steps you must take immediately to secure your system?

Subscribe to our newsletter

Get the latest posts delivered right to your inbox.

Subscribe on LinkedIn