Security Testing
Advanced 22 min read Security Testing

Auth & Session Attacks

Authentication proves who you are, authorization decides what you may do, and sessions carry that identity between requests. Learn the attacks against each link — credential stuffing, brute force, session fixation, IDOR — and the defenses: strong hashing, rotation, secure cookies and server-side ownership checks.

authenticationauthorizationsession managementIDORsession fixationbrute forcebcryptCWE-287CWE-639
Introduction

What is this?

Authentication verifies who a user is, authorization verifies what that user may do, and sessions carry identity across requests. Attacks against this layer target the trust an application places in an authenticated identity — credential stuffing and brute force on login, token theft and fixation on sessions, and missing ownership checks on resources. Even strong passwords fail if tokens are guessable, sessions never rotate or expire, or authorization checks are missing.

Motivation

Why do you need it?

  • A broken authentication flaw turns one valid account — or an attacker's fake one — into a route to sensitive data.
  • The session token is the key to the kingdom: its theft or fixation equals full account takeover.
  • Authorization gaps (IDOR and missing function-level checks) have ranked as the top web risk in recent Top 10 data.
  • Frameworks like OWASP ASVS and PCI-DSS dedicate entire sections to authentication and session management.
  • Every other control sits on top of identity, so a flaw here amplifies every other weakness in the system.
Think about it

Mental model

Imagine

A building badge and a door guard

Think of

A session token and an authorization check

The badge proves you entered the building, but the guard still checks whether you may enter the server room. A system that trusts only the badge lets any badge holder into every room — the same failure as trusting only the session cookie without per-request authorization.

Mechanics

How it works

  • The user presents credentials; the server verifies them against the password hash and issues an opaque, random token or session ID.
  • The client sends the token with every request and the server resolves it back to a user.
  • Authorization middleware checks the resolved identity against the resource's ownership and role rules.
  • Attacks target each link: brute-forcing credentials, predicting or stealing tokens, fixing a session, or skipping the check entirely.
  • Defense: strong password hashing, rate limiting, short-lived rotating tokens, secure cookie flags, and ownership checks on every resource.

The identity chain from login to a returned resource.

Login request
Verify credentials
Issue session token
Authorization check
Resource returned
Reference

Key commands

curl -s -i -X POST "http://sandbox.local/login" -d "username=alice&password=CorrectHorse1"

Capture the Set-Cookie header and inspect its HttpOnly, SameSite and Secure flags.

Set-Cookie: session=...; HttpOnly; SameSite=strict; Secure; Max-Age=1800
curl -s -i -H "Cookie: <session-from-login>" "http://sandbox.local/api/invoices/1"

Probe object-level authorization using a session that does not own the resource.

openssl rand -hex 32

Generate a token with the entropy a good session ID should have.

a3f2c1...e9d8b4c5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0f1e2d3
grep -rn "req.cookies.session\|req.headers.authorization" src/

Audit how the session token is resolved on every request path.

hashcat -a 0 -m 0 hashes.txt rockyou.txt

Educational offline-hash cracking demo — only run against hashes you own to understand why fast hashes fail.

Hands-on

Examples

Secure login, session cookies and an ownership check

Secure login, session cookies and an ownership check
const bcrypt = require("bcryptjs")
const crypto = require("crypto")
// Login: hash comparison never exposes whether the user exists.
app.post("/api/login", async (req, res) => {
const user = await db.users.findByEmail(req.body.email)
const ok = user && (await bcrypt.compare(req.body.password, user.password_hash))
if (!ok) return res.status(401).json({ error: "invalid credentials" })
const token = crypto.randomBytes(32).toString("hex")
await db.sessions.create({ userId: user.id, token })
res.cookie("session", token, {
httpOnly: true,
sameSite: "strict",
secure: true,
maxAge: 30 * 60 * 1000,
})
res.json({ ok: true })
})
// Authorization: ownership + role check on every object access.
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
const invoice = await db.invoices.findById(req.params.id)
if (!invoice) return res.status(404).json({ error: "not found" })
if (invoice.userId !== req.user.id && req.user.role !== "admin") {
return res.status(403).json({ error: "forbidden" })
}
res.json(invoice)
})

Three controls work together. bcrypt.compare runs even when no user exists, so response timing does not reveal whether an email is registered. The session token is 32 random bytes stored server-side and delivered as an HttpOnly, SameSite=strict, Secure cookie with a 30-minute lifetime, so it cannot be read by JavaScript, leaked by cross-site requests or sniffed. Finally, the invoice handler re-checks ownership and role on every request, which is the defense against the IDOR attacks covered in this module.

Real world

In production

  • Sessions are short-lived, rotate on privilege change and are invalidated on logout.
  • Multi-factor authentication is enforced for privileged accounts and risky actions.
  • Cookies carry HttpOnly, Secure and SameSite attributes so tokens are not readable by scripts.
  • Authorization checks run server-side on every request, never only in the frontend.
Guidelines

Best practices

  • Store passwords with bcrypt or argon2, a per-user salt and a high work factor.
  • Use a random, opaque session token; never encode user data into a client-readable token.
  • Set cookies with HttpOnly, Secure, SameSite and an explicit expiry.
  • Rate-limit login, apply account lockout with backoff, and rotate tokens after login and password change.
  • Apply ownership and role checks server-side on every resource endpoint.
Watch out

Common mistakes

  • Trusting the frontend to hide admin buttons while the API skips authorization.
  • Storing passwords as plain text, md5 or a fast hash like sha256.
  • Never invalidating sessions on logout or password change.
  • Using a JWT with a weak secret or an absurdly long lifetime.
Root cause analysis

Common issues

Error
Session cookie is not set in the browser
Root cause

The cookie lacks the Secure flag while the site is served over plain HTTP, or SameSite conflicts with the request.

Fix

Test over HTTPS, or set secure: false in the sandbox only; confirm the domain and path match the request URL.

Error
401 even after a successful login
Root cause

The client is not sending the token, or the server expects a different header name.

Fix

Confirm the cookie/header name in the resolve code matches what the client sends.

Error
User can read another user's records
Root cause

A missing ownership check in the handler.

Fix

Add an owner/role check (see the example), then re-run the IDOR test with a second account.

When things break

Debugging tips

  • Inspect the Set-Cookie header in a proxy to confirm HttpOnly, Secure and SameSite flags.
  • Check whether the session ID changes after login (fixation test) and after password change (rotation test).
  • Log authorization denials server-side to see whether the checks are actually being reached.
Interviews

Interview checkpoint

Practice

Hands-on lab

Auth Bypass & Session Fixation in WebGoat
45 min · advanced
In progress
Objectives
  • Bypass a weak authentication flow in the sandbox
  • Demonstrate a session-fixation scenario and confirm the flaw
  • Probe an object-level authorization endpoint with two accounts
  • Harden the flow with rotation, cookie flags and an owner check

Auth Bypass & Session Fixation in WebGoat

45 min · advanced

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which cookie attribute prevents JavaScript from reading the session token?

2

Storing a session token in localStorage is safe as long as the token expires quickly.

3

You log in twice from the same browser and the session ID does not change after the second login. Which attack does this enable?

Quick reference

Cheat sheet

Auth & session hardening
bcrypt.compare(pw, hash)Slow hash, constant-time compare
crypto.randomBytes(32).toString('hex')Opaque, unguessable token
httpOnly: true, sameSite: 'strict', secure: trueCookie flags
rotate session on loginDefeats fixation
rotate on privilege changeDefeats privilege escalation reuse
owner + role check per requestDefeats IDOR
Go deeper

Official documentation