DEV Community

krishnadaspc
krishnadaspc

Posted on

How CSRF Token protects your web application

We are going to look how CSRF tokens works in a real node express application and how it protects the app from cross site request forgery. If you would like to see the video version of this post you can watch it here.
Watch video here

What is cross site request forgery?

When a web server is receives a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for a hacker to send requests to the web server which will be treated as a genuine request. This can be done via a Form submit, URL, image load, XMLHttpRequest, etc. and can result in data breach or unintended code execution. In this post we are going to explain a form submit kind of attack and how CSRF tokens prevents this.

Code set up

There are two fresh express applications running. One is running on port 3000 which is App1 and another is running on port 5000 which is App2. Both of these applications are created using the express generator.

App1 Code snippets

Install the npm csurf

Enable the csrf middleware for the application in app.js

var csrf = require('csurf')
// setup route middlewares
app.use(cookieParser('fsgdesgsdYYFCCXXX'));
app.use(csrf({ cookie: true }))
Enter fullscreen mode Exit fullscreen mode

Setting up the routes for the App1. Code from routes/index.js

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: "App1, CSRF Demo", csrfToken: req.csrfToken() })
});
router.post('/process', function (req, res) {
  res.send('csrf is valid, data is being processed')
})
Enter fullscreen mode Exit fullscreen mode

In the above code we are generating the csrfToken and passing it to the view where we load our form with csrfToken: req.csrfToken()

In the view we use handlebars as our templating engine and csrf token is added as a hidden input field.

<h1>{{title}}</h1>
<p>Welcome to {{title}}</p>
<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="{{csrfToken}}">

  name: <input type="text" name="name">
  <button type="submit">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

When we start the App1 we can see a form loaded with the generated csrf token if you check the html view source of the page.
Alt Text

Alt Text

and submit the form with some data. You can see this result as csrf token is validated and correct.
Alt Text

How token protects the app?

Now let's remove the token generation and see how this CSRF middle-ware protects our application. Change the code in app1/routes/index.js like this. Now we pass csrf as an empty string.

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: "App1, CSRF Demo", csrfToken: '' })
});
Enter fullscreen mode Exit fullscreen mode

Now if you submit the form you will get an error message like this.
Alt Text

Now server rejects the request as it cannot find a valid token in the request and now we are protected from such kind of attacks.

Attack request from App2

Now let's mimic an attack from another domain/application. In this example which is App2

For the time being just disable the csrf middleware in App1. Comment these lines in app1/app.js

// app.use(csrf({ cookie: true }))
Enter fullscreen mode Exit fullscreen mode

In App2 home route we also have the same form but the form submit action is the url of App1

<h1>{{title}}</h1>
<p>Welcome to {{title}}</p>


<form action="http://localhost:3000/process" method="POST">

  name: <input type="text" name="name">
  <button type="submit">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Start the server App2 which is running on port 5000. You can see the form but now when you submit the form it is accepted as App1 currently do not have CSRF middleware enabled.

Alt Text

Alt Text

Now just re enable our csrf middleware in App1. Un comment this line

app.use(csrf({ cookie: true }))
Enter fullscreen mode Exit fullscreen mode

And now when you submit the form from App2 you will get this error page only. So we are now protected.
Alt Text

That's how a CSRF token protects in a real application. You can find the full source code here Github Code Link

You can follow me on my twitter here KrishnadasPC

Discussion (0)