In Aurelia, there doesn't seem to be any support for CSRF protection yet, as opposed to AngularJS's XSRF-TOKEN
header which is set automatically on all XHR requests by the AngularJS framework.
How should I go about protecting an Aurelia app from CSRF attacks? Should I roll my own support based on the OWASP CSRF Prevention Cheat Sheet, or are there any alternatives out there for Aurelia already?
You should be able to do this yourself fairly easily by using Aurelia's HTTP interceptors (see examples in the docs). Before every request, you can send your token. This can be done with both the conventional aurelia-http-client
and the new standard aurelia-fetch-client
.
Your code might look like this:
export class MyRestAPI {
static inject () { return [HttpClient]; } // This could easily be fetch-client
constructor (http) {
this.http = http.configure(x => {
x.withBaseUrl(myBaseUrl);
x.useStandardConfiguration();
x.withInterceptor({
request: function (request) {
request.headers.set('XSRF-TOKEN', myAwesomeToken);
return request;
}
});
});
}
...
}
On every request, your token would be sent. You'd have to handle the validation on the server side. You could easily set up your code so that your initial request could grab a token, or you could pass a token back as part of your authentication payload, or if you wanted to you could even store a token in the browser's localstorage and use it that way.
You could even go a step further and implement JWT authentication. If you're using node.js, I have a small blog post that describes how I implemented JWT in Express. There's a plugin on Github called aurelia-auth that handles JWT, and there's a blog post on its implementation on the Aurelia blog as well.
Here is a sample interceptor that reads the token from the response header if it exists and sets it automatically on every request that needs it.
import {Interceptor, HttpResponseMessage, RequestMessage} from "aurelia-http-client";
class CsrfHeaderInterceptor implements Interceptor {
private static readonly TOKEN_HEADER = 'X-CSRF-Token';
private latestCsrfToken: string;
response(response: HttpResponseMessage): HttpResponseMessage {
if (response.headers.has(CsrfHeaderInterceptor.TOKEN_HEADER)) {
this.latestCsrfToken = response.headers.get(CsrfHeaderInterceptor.TOKEN_HEADER);
}
return response;
}
request(request: RequestMessage): RequestMessage {
if (this.latestCsrfToken) {
if (['POST', 'PUT', 'PATCH'].indexOf(request.method) >= 0) {
request.headers.add(CsrfHeaderInterceptor.TOKEN_HEADER, this.latestCsrfToken);
}
}
return request;
}
}
You register it in your http/fetch client with for example:
httpClient.configure((config) => {
config
.withBaseUrl("/api/") // adjust to your needs
.withHeader('Accept', 'application/json') // adjust to your needs
.withHeader('X-Requested-With', 'XMLHttpRequest') // adjust to your needs
.withInterceptor(new CsrfHeaderInterceptor());
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With