Every big attack class below is the same picture: data crossing a boundary into an interpreter
that parses it as instructions. The red arrow is the moment of danger.
The left side glues the user value into the query text, so the value can grow new branches in the
parse tree (red). The right side keeps the template fixed and binds the value to a single leaf — it
can never add a node.
The same three payloads hit two filters. The blocklist (top) leaks anything it forgot to list; the
allowlist (bottom, red frame) passes only the one input matching the good pattern.
A single HTTP request must pass authentication, then authorization on this specific object,
before it touches data. The red diamond is the per-request check people forget.
Maps each vulnerability class to the defenses that fit it. Read a row: the prevention column
(red) is always the primary move; detection and response are backups, never substitutes.
A user who is logged in is therefore authorized to view any page in the app.
False — being logged in is authentication (who you are); each page still needs an authorization check (what you may do). Skipping that check is Broken Access Control (A01).
Parameterized queries protect you by escaping dangerous characters in the input.
False — they don't escape at all; the driver compiles the query template first, then binds the value on a separate channel, so the input is never parsed as SQL regardless of its characters.
Blocklisting characters like ', ;, and DROP is a reasonable primary defense against injection.
False — a blocklist must enumerate the infinite set of bad inputs (encodings like %27, comments /**/, UNION SELECT without quotes), so bypasses always exist; allowlist or parameterize instead.
HTTPS on the login page means passwords are stored securely in the database.
False — HTTPS protects data in transit; storage security is a separate concern requiring a slow salted hash like bcrypt/argon2. Transport encryption says nothing about the database.
If input passed client-side (JavaScript) validation, the server can trust it.
False — the client is fully under the attacker's control; they can bypass the browser and send any request directly, so all validation must be repeated server-side.
Encoding a value for HTML makes it safe to use in any context (SQL, shell, URL).
False — encoding is context-specific; HTML encoding does nothing against SQL injection. Each destination interpreter (HTML body, HTML attribute, SQL, shell) needs its own encoding.
The OWASP Top 10 is a checklist you complete to become "secure."
False — it is awareness guidance, a frequency-ranked list of risk categories, not a pass/fail list of specific bugs to tick off.
MD5 is fine for password hashing because it is a one-way function.
False — MD5 is one-way but fast, making brute force cheap, and unsalted hashes fall to rainbow tables; password storage needs a deliberately slow, salted algorithm.
Authorization must always come before authentication.
False — it's the reverse: you must authenticate first (know who the subject is) before you can decide what they may do. Anonymous access is just AuthZ with subject = "anonymous."
A per-user salt keeps passwords secret from an attacker who steals the database.
False — a salt doesn't hide the password; it makes identical passwords hash differently, defeating rainbow tables and forcing the attacker to crack each hash separately.
q = "SELECT * FROM users WHERE id = " + user_id — what's wrong?
User input is concatenated into the query string, so it can alter the parse tree (e.g. 1 OR 1=1). Fix: use a parameterized query with a bound placeholder.
if user.is_logged_in: return db.orders[order_id] — what's the flaw?
It checks authentication but never checks ownership; any logged-in user can change order_id and read others' data (IDOR). Add if order.owner_id != current_user.id: return 403.
page += "<div>" + bio + "</div>" rendering a user bio — why unsafe?
The bio is placed raw into HTML, so <script> inside it will execute (XSS). It must be output-encoded for the HTML-body context first.
store(user, password) — plaintext storage. Why is a leak catastrophic here?
A database breach instantly exposes every real password, and users reuse passwords, so the damage spreads to other sites. Store a slow salted hash, never the password itself.
A validator that rejects strings longer than 200 chars but accepts any characters — sufficient against injection?
No — length limits alone don't constrain shape; a short malicious payload like '-- still passes. You need allowlist pattern matching or parameterization.
allow if role == "admin" or role == "user" used to gate a delete-all endpoint — spot the over-grant.
It authorizes ordinary users for a destructive admin action, violating the Principle of Least Privilege (Principle of Least Privilege); the endpoint should be admin-only and default-deny.
Why is allowlisting called stronger than blocklisting?
You enumerate the small, finite set of good inputs instead of the infinite set of bad ones, so anything unexpected is rejected by default.
Why does parameterization drive parse-tree injection to zero?
The parse tree is fixed from the template alone; the user value binds to a single leaf node and can never add or change a node in the tree.
Why must authorization be re-checked on every request, not just at login?
HTTP is stateless and the client controls each request, so a user can change a URL or ID at any time; per-request, per-object checks are the only way to stop IDOR.
Why is a slow, tunable work factor desirable in a password hash when speed is usually good?
Slowness barely affects one legitimate login but makes mass guessing of stolen hashes economically infeasible, and the tunable factor lets you raise cost as hardware improves. See Cryptography Basics.
Why do most breach categories reduce to "data treated as instructions"?
Injection, XSS, and path traversal all happen when untrusted data crosses into an interpreter that parses it as code; constraining data before that boundary neutralizes the whole class.
Why is the airport passport-vs-ticket analogy useful for AuthN vs AuthZ?
The passport (AuthN) proves identity but grants no seat; the ticket check (AuthZ) grants access to one specific flight — showing identity alone is never permission.
For a public, unauthenticated endpoint, is authorization irrelevant?
No — public access is still an authorization decision where the subject is "anonymous"; you consciously allow it rather than skipping the check entirely.
If two users happen to choose the same password, what does the salt change about their stored hashes?
With per-user salts the two stored hashes are completely different, so an attacker cannot tell the passwords match or reuse one crack across both.
An input field is empty — should validation pass, fail, or depend?
It depends on the field's allowlist rule: empty may be valid for an optional field but must be rejected where a value is required; degenerate/empty inputs must be handled explicitly, never assumed.
A request arrives with a valid session token but for a resource that was deleted — what should the response reflect?
Authentication succeeds (token is valid) but authorization/lookup on a missing object must fail cleanly (404/403), never leak whether the object ever existed to an unauthorized user.
If validation and output encoding are both applied, is one redundant?
No — they defend different boundaries: validation constrains data at input, encoding neutralizes it at each output context; defense-in-depth wants both, since a value valid on input can still be dangerous in HTML.
Recall One-line self-test
Cover the answers, go top to bottom, and speak a reason for each. Any item where you said
"true/false" without a "because" is a gap — reread that section of the parent note.