Scroll down to the script below, click on any sentence (including terminal blocks!) to jump to that spot in the video!Cool, got it! Show me the script!
This Chapter isn't quite ready yet
Rest assured, the gnomes are hard at work on completing this video
We've gotta talk about one more thing: security. Specifically, CSRF attacks.
Imagine if a malicious person built an HTML form on a totally different site, but
action="" attribute to a URL on our site. Then, what if some user, like
me, who is logged into our site, was tricked into submitting that form? Well, the
form would submit, I would of course be authenticated, and the request would be
successful! That's a problem! The malicious user was basically able to make a request
to our site logged in as me! They could have done anything!
So, how can we protect against this in an API? The answer... you might not need to. If you follow two rules, then CSRF attacks are not possible.
First, disallow AJAX requests from all domains except for your domain. Actually, this is just how the Internet works: you can't make AJAX requests across domains. If you do need to allow other domains to make AJAX requests to your domain, you do that by setting CORS headers. If you're in this situation, just make sure to only allow specific domains you trust, not everyone. This first rule prevents bad AJAX calls.
For the second rule, look at our API:
newRepLogAction(). Notice that the body of the request is JSON. This is the second
rule for CSRF protection: only allow data to be sent to your server as JSON.
This protects us from, for example, bad forms that submit to our site. Forms cannot
submit their data as JSON.
If you follow these two rules - which you probably do - then you do not need to
worry about CSRF. But, to be fully sure, we are going to add one more layer:
we're going to force all requests to our API to have a
application/json. By requiring that, there is no way for a bad request
to be made to our site, unless we're allowing it with our CORS headers.
Oh, and important side note: CSRF attacks only affect you if you allow session-based authentication like we're doing, or HTTP basic authentication. If you require an API token, you're also good!
We're going to require the
Content-Type header by creating an event subscriber,
so that we don't need to add this code in every controller. First, to speed things
up, install MakerBundle:
composer require maker --dev
When that finishes, run:
php bin/console make:subscriber
ApiCsrfValidationSubscriber. And, listen to the
Done! This made one change: it created a new class in
Awesome! Because we're listening to
method will be called on every request, before the controller. At the top of
the method, first say if
!$event->isMasterRequest(), then return. That's an internal
detail to make sure we only run this code for a real request.
Next, we do not need to require the
Content-Type header for safe HTTP methods,
like GET or HEAD, because, unless we do something awful in our code, these requests
don't change anything on the server. Add
$request = $event->getRequest(). Then,
$request->isMethodSafe(false), just return again.
false part isn't important: that's a flag for a backwards-compatibility layer.
Perfect! Next, we need to determine whether or not this request is to our api.
We'll do that with a cool annotation trick. Then, we'll make sure the
header is set to