As browsers automatically send credentials like session cookies with HTTP requests to the server where cookies were received from, attackers can create malicious web pages which generate forged requests that are indistinguishable from legitimate ones.
For example, CSRF vulnerability can be exploited on profile form on the insecure demo application.
To exploit it:
<html lang="en"> <head></head> <body> <form method="POST" action="http://TARGET_APP_URL_HERE/profile"> <h1> You are about to win a brand new iPhone!</h1> <h2> Click on the win button to claim it...</h2> <input type="hidden" name="bankAcc" value="9999999"/> <input type="hidden" name="bankRouting" value="88888888"/> <input type="submit" value="Win !!!"/> </form> </body> </html>Note: A sample app containing form for CSRF attack on NodeGoat app is available here.
Express csrf middleware provides a very effective way to deal with csrf attack. By default this middleware generates a token named "_csrf" which should be added to requests which mutate state (PUT, POST, DELETE), within a hidden form field, or query-string, or header fields.
If using method-override middleware, it is very important that it is used before any middleware that needs to know the method of the request, including CSRF middleware. Otherwise an attacker can use non-state mutating methods (such as GET) to bypass the CSRF middleware checks, and use method override header to convert request to desired method.
When form is submitted, the middleware checks for existence of token and validates it by matching to the generated token for the response-request pair. If tokens do not match, it rejects the request. Thus making it really hard for an attacker to exploit CSRF.
server.js
includes the express CSRF middleware after session is initialized. Then creates a custom middleware to generate new token using
req.csrfToken();
and exposes it to view by setting it in
res.locals
//Enable Express csrf protection app.use(express.csrf()); app.use(function(req, res, next) { res.locals.csrftoken = req.csrfToken(); next(); });Next, this token can be included in a hidden form field in
views/profile.html
as below.
<input type="hidden" name="_csrf" value="{{ csrftoken } }">