From e2a17db8da0d5caf61f06d2aaa7d7082bc765c11 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Sat, 4 May 2019 13:38:41 -0400 Subject: [PATCH] Enable Request Forgery Protection in `test` If we're feeling skeptical that the application's behavior _does_ meet the criteria as defined in our test suite, we can boot it locally and visit it in a web browser ourselves: ```bash $ rails server --port 3000 ``` Once it's running, we can follow the instructions described in our system test by opening a web browser and: * visiting [http://localhost:3000/][] * clicking on "Share a Note" * filling in the text box labelled "Message" with the value "Hello, World" * clicking on "Share" Oh no! Surprisingly, our server responds to our submission with an error page. If we inspect our `rails server` process log, it contains the following output: ``` Started POST "/notes" for ::1 at 2019-05-04 13:37:35 -0400 Processing by NotesController#create as HTML Parameters: {"content"=>"Hello, World"} Can't verify CSRF token authenticity. Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 461) ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): ``` By default, Rails comes with some security-minded default behavior. In this case, the error's mention of being unable to `verify CSRF token authenticity` stems from Rails' [Cross Site Request Forgery Protection][csrf]. The Rails Security Guidelines describe CSRF: > This attack method works by including malicious code or a link in a > page that accesses a web application that the user is believed to have > authenticated. If the session for that web application has not timed > out, an attacker may execute unauthorized commands. By default, this protective measure is in place in every [Rails Environment][rails-env] _except for `test`_. To ensure that _all_ environments have this protection in place, this commit [enables CSRF protection in `test.rb`][configuring-controllers]. When we run the test again, it is no longer passing. It fails with a new error: ``` Error: UserSharesAMessageTest#test_visiting_the_index: DRb::DRbRemoteError: ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken) ``` In this instance, regressing from the Green Phase to the Red Phase has a positive effect. Since our `test` environment's behavior did not have [parity] with the other environments, a test failure uncovering that fact is helpful and important to address. In cases like this that uncover important gaps in behavior, we can consider transitioning from the Green Phase to Red Phase as a temporary (but helpful!) detour toward the Refactoring Phase. [csrf]: https://guides.rubyonrails.org/v5.2/security.html#cross-site-request-forgery-csrf [rails-env]: https://guides.rubyonrails.org/v5.2/configuring.html#creating-rails-environments [configuring-controllers]: https://guides.rubyonrails.org/v5.2/configuring.html#configuring-action-controller [parity]: https://12factor.net/dev-prod-parity --- config/environments/test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 4ff9489..187047f 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -27,7 +27,7 @@ config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment. - config.action_controller.allow_forgery_protection = false + config.action_controller.allow_forgery_protection = true # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test