See https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet and https://seclab.stanford.edu/websec/csrf/csrf.pdf for details on what CSRF is and available countermeasures.
Artifacts are available via jcenter:
repositories {
jcenter()
}
Your configuration may vary, but here's a solid starting point: checking that the Origin
header is your actual site,
and enforcing that a custom header is present (which your front-end JavaScript/etc is presumably sending).
install(CsrfProtection) {
validate(OriginMatchesKnownHost("https", "my-service.com"))
validate(HeaderPresent("X-Some-Custom-Header-Your-Frontend-Sends"))
}
// ... configure routing ...
routing {
csrfProtection {
get("/protected") {
// ...
}
}
get("/unprotected") {
// ...
}
}
A first step is to validate that the origin of the request (represented by the Origin
header) matches
the host that your service is deployed at, e.g. https://my-service.com
. See OriginMatchesKnownHost
for an
out-of-the-box implementation.
If configuring the service to know its deployment host ahead of time is infeasible, another approach would
be to inspect the Host
or X-Forwarded-Host
headers and ensure that they match Origin
. See
OriginMatchesHostHeader
.
Referer
(sic) is another header that can sometimes contain origin info, but with plain HTTP (not HTTPS) it is
sometimes stripped out by proxies, and the ReferrerPolicy
response header can configure browsers to not send a
Referer
, so we just stick with Origin
.
Another layer of defense is to require a custom header to be sent. This is feasible when the intended client is a
purely AJAX-driven or otherwise has tight control over requests. Typical CSRF request would not have the
opportunity to set any headers beyond what the browser provides by default. See HeaderIsPresent
for an implementation
of this.