🔀 Cross-Site Request Forgery

Updated at 2024-02-18 18:19

Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to submit a request to an application against which they are currently authenticated.

"Non-safe" HTTP methods must use CSRF protection when cookies are used. GET, HEAD, OPTIONS, and TRACE methods are defined to be "safe". As they are not requests for modification of something. This assumes that the application uses HTTP methods correctly.

Security critical actions should require even further user action. Re-authentication, CAPTCHA, one-time tokens, separate device confirm, etc.

Securing the response is done using SSL and Cache-Control: no-store. This is the best you can do; once the sensitive data gets to the client, there's no way to stop them from doing whatever they want with it.

You should have a pre-session before login. Allows using CSRF protection even before login. You must destroy the pre-session after login to prevent session fixation attacks.

Login forms need CSRF protection too. Attacker can make a victim log in to attacker account and the lure them to add their credit card which the attacker can the use for purchases.

Synchonizer Token Pattern

1. Backend stores a CSRF token in the user-specific session.
2. Backend sends the token to the frontend:
    - In a hidden form field.
    - In a HTTOOnly off cookie.
3. If the token is in a cookie, the frontend duplicates it to a form field
   or custom, non-cookie header.

Signed Double-Submit Cookie

Signed Double-Submit Cookie if using something stateless like JWTs.

1. Backend sends a (signed) CSRF cookie with HTTPOnly off.
2. Frontend duplicates that cookie to body data or custom header.
3. Backend checks if these both match; cookie and custom header / field.

(securely signed tokens are better as some attacks can add headers / fields)
secret = readEnvironmentVariable("CSRF_SECRET") // HMAC secret key, only backend
sessionID = session.sessionID                   // or JWT payload random
randomValue = cryptographic.randomValue()

// create the token
message = sessionID + "!" + randomValue // HMAC message payload
hmac = hmac("SHA256", secret, message)  // generate the HMAC hash
csrfToken = hmac + "." + message        // message is plain to verify later

// send the token to frontend
response.setCookie("csrf_token=" + csrfToken + "; Secure) // HTTPOnly off

// frontend sends the token back both 1) in cookies and 2) custom header / field