Skip to main content
PProfileMatch

OWASP Top 10: Authentication, Crypto Failures and Misconfiguration

CybersecurityLesson 2 of 45 min read

What you'll learn

  • Identify common authentication and session management failures
  • Choose appropriate cryptography for tokens, stored secrets and data in transit
  • Audit HTTP response headers and server settings for risky defaults
  • Describe secure-by-default configuration for cookies, errors and environments

On this page

  1. Authentication failures
  2. Cryptographic failures
  3. Security misconfiguration
  4. Common mistakes
  5. How this shows up in real projects and interviews

A film club sells tickets through a small site it built over a weekend. Three months later a member reports that she received a password-reset link which still worked after she had used it twice. Someone else points out that the staging site, with real members in its database, loads over plain HTTP and prints a full stack trace on errors. Three separate flaws, one shared cause: the defaults were never reviewed. Each belongs to a theme the OWASP Top 10 (current edition) calls out, and none of them needs a clever attacker.

Authentication failures

This theme covers everything that lets someone be treated as a user they are not. The classic causes are accepting weak or breached passwords, no protection against automated guessing, session identifiers that are predictable or never expire, reset and recovery flows that are weaker than the login, and exposing session ids in URLs. Fixes line up with each cause:

  • Throttle login attempts with growing delays, and alert on bursts of failures.
  • Offer multi-factor authentication and require it for admin accounts.
  • Check new passwords against known-breached lists and enforce minimum length rather than composition rules.
  • Issue a fresh session id after login, expire sessions on logout and after inactivity, and invalidate them on password change.
  • Make reset tokens random, single-use, short-lived and tied to the account, and send the same response whether or not the email exists.

Cookies carry sessions, so their flags matter. In HTTP response form, a well-configured session cookie looks like this. The HttpOnly flag keeps scripts from reading it, Secure restricts it to HTTPS, and SameSite limits cross-site sending, which reduces cross-site request forgery.

response header
Set-Cookie: session=<random-id>; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600

If your app uses token-based sessions rather than server-side ones, the same ideas apply to signing, expiry and storage; see JWT authentication for the specifics.

Cryptographic failures

The theme used to be described as "sensitive data exposure", and the shift in wording is instructive: the root cause is usually weak or missing cryptography, not the exposure itself. Typical forms are data sent over plain HTTP, obsolete algorithms (MD5 or SHA-1 for passwords or signatures), hard-coded keys in source, passwords stored unhashed or with fast hashes, predictable random numbers for tokens, and storing data that was never needed.

The random-number point is easy to get wrong in code. General-purpose generators are designed for speed and statistical spread, and their output can be reproduced from a seed. For anything an attacker must not guess (reset tokens, session ids, invite codes) use the operating system's cryptographic generator.

tokens.py
import random
import secrets

# random is a Mersenne Twister: fine for shuffling a playlist, wrong for secrets.
# secrets draws from the operating system's cryptographic generator.
reset_token = secrets.token_urlsafe(32)
print("token length:", len(reset_token))
print("two tokens differ:", secrets.token_urlsafe(32) != secrets.token_urlsafe(32))

# Predictability demo: seed the plain generator twice and get the same "random" value.
random.seed(1234)
first = random.getrandbits(32)
random.seed(1234)
second = random.getrandbits(32)
print("same seed, same output:", first == second)

Output

token length: 43
two tokens differ: True
same seed, same output: True

A sensible baseline: HTTPS everywhere with HSTS, a modern authenticated encryption mode when you must encrypt data at rest, passwords hashed with a slow salted algorithm (covered in passwords, MFA and hashing), keys kept in a secrets manager or environment-specific store and never in a repository, and a rotation plan. Prefer vetted libraries over writing your own cryptography, and delete data you do not need, since data you never stored cannot leak.

Security misconfiguration

Most software ships with settings aimed at making things easy for developers: sample accounts, verbose errors, open cloud storage, directory listings, default admin pages. Misconfiguration is leaving those in place, or drifting out of line between environments. It is the least glamorous theme and one of the most reliable sources of real incidents, because it needs no bug in your code.

Headers are a quick, visible place to start. This script audits a sample response for missing protective headers and for version information that tells outsiders exactly which software to look up flaws for.

header_audit.py
EXPECTED = {
    "strict-transport-security": "force browsers to use HTTPS",
    "content-security-policy": "limit where scripts and frames can load from",
    "x-content-type-options": "stop MIME sniffing (should be 'nosniff')",
    "referrer-policy": "limit URLs leaked to other sites",
}
LEAKY = ("server", "x-powered-by")

def audit(response_headers: dict[str, str]) -> list[str]:
    seen = {k.lower(): v for k, v in response_headers.items()}
    findings = []
    for name, why in EXPECTED.items():
        if name not in seen:
            findings.append(f"missing {name}: {why}")
    for name in LEAKY:
        if name in seen and any(ch.isdigit() for ch in seen[name]):
            findings.append(f"{name} reveals a version: {seen[name]}")
    return findings

sample = {
    "Content-Type": "text/html",
    "Server": "Apache/2.4.41",
    "X-Powered-By": "PHP/7.4.3",
    "X-Content-Type-Options": "nosniff",
}
for finding in audit(sample):
    print(finding)

Output

missing strict-transport-security: force browsers to use HTTPS
missing content-security-policy: limit where scripts and frames can load from
missing referrer-policy: limit URLs leaked to other sites
server reveals a version: Apache/2.4.41
x-powered-by reveals a version: PHP/7.4.3

Common mistakes

  • Debug mode on in production. Symptom: an error page showing stack traces, file paths and sometimes connection strings. Fix: generic error pages to users, details to logs only.
  • Real data in staging with weaker controls. Symptom: a staging database leaks real members. Fix: synthetic or masked data, and the same access rules as production.
  • Secrets committed to the repository. Symptom: a key found in git history months later, still valid. Fix: rotate it first, then move secrets to a manager and add secret scanning.
  • Default credentials on admin consoles or databases. Symptom: an internet-facing panel that accepts the vendor default. Fix: change at install, restrict by network, disable what you do not use.
  • Reusing a reset token after use. Symptom: an old email link still logs someone in. Fix: single-use, expiring tokens, invalidated on use.

How this shows up in real projects and interviews

In interviews these themes appear as design questions: "how would you build password reset?" and "how do you manage secrets for a service?" Real teams meet them as findings in a penetration test or a cloud security scanner, and the fixes are mostly configuration and process, which is why they get fixed late. A habit worth building is keeping environment configuration in version control (without the secrets), so drift between staging and production can be seen in a diff. If you work on pipelines, CI/CD is the natural place to run secret scanning and dependency checks.

Try it yourself

Write a reset-token design for a small site: how the token is generated, how long it lives, whether it is single-use, what the page says if the email does not exist, and what happens to existing sessions when the password changes.

Show a hint

Use secrets.token_urlsafe, store only a hash of the token, set expiry to minutes not days, and return the same message for known and unknown emails to avoid revealing who has an account.

Key takeaways

  • Authentication failures include weak passwords, unlimited guessing, long-lived sessions and weak reset flows.
  • Set HttpOnly, Secure and SameSite on session cookies, and issue a new session id after login.
  • Use the operating system's cryptographic random source for anything that must not be guessed.
  • Most misconfiguration is defaults left in place; make secure settings the baseline and review them per environment.
  • Keep secrets out of source control and rotate any that were ever committed.

Test yourself

A trick from this lesson's ride: HttpOnly: no script peeking. Secure: HTTPS van only. SameSite: no cross-site errands. Four more tricks like it wait along the route, each followed by a question.

Ride this lesson

Frequently asked questions

What are cryptographic failures in the OWASP Top 10?

They are weaknesses in how data is protected: plain HTTP, outdated algorithms, hard-coded keys, weak password hashing or predictable random values. The theme replaced the older "sensitive data exposure" wording to point at the root cause.

What is security misconfiguration with an example?

It means insecure settings left in place, such as debug mode in production, default admin passwords, open cloud storage or verbose error pages that show internal paths. These need no code bug, only a configuration review to find.

Which cookie flags should a session cookie have?

At minimum HttpOnly (so scripts cannot read it), Secure (HTTPS only) and a SameSite setting such as Lax or Strict. Also give it a sensible expiry and issue a new value after login.