Introduction

Cross-site request forgeries are a sort of malicious exploit in which an authenticated user is used to execute unauthorised commands. Thankfully, OstroJS makes it simple to guard against cross-site request forgery (CSRF) threats.

An Explanation Of The Vulnerability

Let's look at an example of how this vulnerability might be abused if you're not familiar with cross-site request forgeries. Consider a /user/email route in your application that accepts a POST request to alter an authenticated user's email address. This route most likely expects the user's preferred email address to be entered into an email input form.

A malicious website could generate an HTML form that points to your application's /user/email route and submits the malicious user's own email address if you don't utilise CSRF protection:

<form action="https://your-application.com/user/email" method="POST">
    <input type="email" value="malicious-email@example.com">
</form>

<script>
    document.forms[0].submit();
</script>

If the malicious website submits the form automatically as the page loads, the malicious user simply needs to persuade an unwary user of your application to visit their site, and their email address will be modified in your application.

To avoid this flaw, we must look for a secret session value that the malicious application cannot access in every incoming POST, PUT, PATCH, or DELETE request.

Preventing CSRF Requests

For each active user session controlled by the application, OstroJS creates a CSRF "token" automatically. This token is used to confirm that the user who has been authenticated is the one who is making the requests to the application. A malicious programme cannot access this token since it is kept in the user's session and changes each time the session is refreshed.

The CSRF token for the current session can be found in the request's session:


route.get('/token', function ( {request}) {
   let token = request.session.token();

    // ...
});

You should add a hidden CSRF _token field in your HTML form whenever you define a "POST", "PUT", "PATCH", or "DELETE" HTML form in your application so that the CSRF protection middleware can validate the request. 

<form method="POST" action="/profile">
    
    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="<%= helpers.csrf_token() %>" />
</form>

The app/http/middleware/verifyCsrfToken middleware, which is included by default in the web middleware group, checks that the token in the request input matches the token saved in the session. When these two tokens match, we know the request was initiated by the authenticated user.

Excluding URIs From CSRF Protection

You may want to exclude a group of URIs from CSRF protection at times. If you use Stripe to process payments and use their webhook system, you'll need to disable CSRF protection on your Stripe webhook handler route since Stripe won't know what CSRF token to send to your routes.


These kind of routes should usually be placed outside of the web middleware group that the app/providers/routeServiceProvider applies to all routes in the routes/web.js file, in most cases. You may alternatively omit the routes by adding their URIs to the VerifyCsrfToken middleware's $except property:

const  Middleware = require('@ostro/foundation/http/middleware/verifyCsrfToken')

class VerifyCsrfToken extends Middleware {
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
     $except = [
        'stripe/(.*)',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}
module.export = VerifyCsrfToken

 

 

CSRF Tokens & SPAs

If you're creating an SPA using OstroJS as the backend API, you should read the api documentation to learn how to authenticate with your API and defend against CSRF attacks.

 

X-CSRF-Token

The app/http/middleware/verifyCsrfToken middleware will additionally check for the X-CSRF-TOKEN request header in addition to the CSRF token as a POST parameter. For example, you might save the token in an HTML meta tag:

<meta name="csrf-token" content="<%= helpers.csrf_token() %>">

Then you can tell a library like jQuery to add the token to all request headers automatically. This provides easy, quick CSRF security for your old JavaScript-based AJAX applications:

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

X-XSRF-Token

OstroJS keeps track of the current CSRF token in an encrypted XSRF-TOKEN cookie that is sent along with every response it generates. The cookie value can be used to set the X-XSRF-TOKEN request header.

Because certain JavaScript frameworks and libraries, such as Angular and Axios, automatically insert its value in the X-XSRF-TOKEN header on same-origin requests, this cookie is mostly supplied for developer convenience.