📜 ⬆️ ⬇️

Defending Revel from CSRF attacks



After playing with Revel and realized what kind of freak it is, it's time to learn how to prepare it for production in terms of security. This note may well be used in any web application, but I will tell on the example of a simple application on Revel.

In general, the problem lies in the fact that there is a class of attacks on the Internet called Cross-Site Request Forgery (abbr. CSRF). If you are not familiar with them, please turn your attention. I will give a short excerpt from the wiki:

CSRF is a type of attack on website visitors that uses the disadvantages of the HTTP protocol. If the victim enters the site created by the attacker, a request is secretly sent to another server (for example, to the server of the payment system), performing some kind of malicious operation (for example, transferring money to the attacker's account). To carry out this attack, the victim must be authenticated on the server to which the request is sent, and this request must not require any confirmation from the user, which cannot be ignored or forged by the attacking script.

rice An example of a CSRF attack on a bank site
')
I also recommend reading typical errors when protecting sites from CSRF attacks .

On a fresh Revel application, the CSRF attacks successfully pass because there is no protection initially.

So, let's start kutit with gopher - installation protection


Comrades from Revel offer us a ready-made module to protect github.com/revel/modules/tree/master/csrf/app with installation instructions:
CsrfFilter enables CSRF request token creation and verification.

Usage:
1) Add `csrf.CsrfFilter` to the app's filter (it must come after the revel.SessionFilter).
2) Add CSRF fields with the template tag `{{csrftoken. }} `. The filter adds it a little bit. Ajax support provided through the `X-CSRFToken` header.

Actually everything is OK! Added a filter in the init.go application for this instruction ... And it will not work unless your browser sends Referer in the header . Therefore, we will skip the entire installation of this filter in this note and proceed to an alternative option.

One of the options proposed in the Revel bug tracker on CSRF was a project: github.com/cbonello/revel-csrf . The installation principle is simple:

First, we pump everything into GOPATH
go get github.com/cbonello/revel-csrf 


Next in /app/init.go we add a line to the import section:
 import ( "github.com/cbonello/revel-csrf" "github.com/revel/revel" ) 


And in the init () function in the same file /app/init.go we add this filter:
 func init() { // Filters is the default set of global filters. revel.Filters = []revel.Filter{ ... revel.SessionFilter, // Restore and write the session cookie. revel.FlashFilter, // Restore and write the flash cookie. HeaderFilter, // Add some security based headers csrf.CSRFFilter, // CSRF prevention. <---------------------------- revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie. ... } ... } 


Installation is almost ready! Now all methods except GET, HEAD, OPTIONS, TRACE, WS are considered “unsafe” and in the absence of the generated token in the request there will be 403 errors.

How to transfer a token


Basic unsafe requests are generated using web forms. Accordingly, logchino now insert a hidden field containing a token into each form:
 <form id="login-form" class="form-vertical" action="{{url "App.ConfirmLogin"}}" method="post"> <input type="hidden" name="csrf_token" value="{{.csrf_token }}"> ... </form> 

For simplicity, you can take the function for the template engine from the module from the Revel command.

Most actions are solved this way - by embedding a hidden field in a web form. But there is a category of actions that do not require sending a web form, but are unsafe from a business logic point of view. For example: user logon link / logout. To carry out an attack on such an action is very simple, therefore, the processing of such an action must be transferred from the secure GET method to the POST method, which is unsafe for us. To do this, in the / conf / routes file we add our action only for the POST method:
 POST /logout App.Logout 


Now you need to make the links suitable for working with POST methods. For such cases, you can use a good wrapper for working with ajax in RoR: github.com/rails/jquery-ujs

Install to your project through Bower:
 $ bower install jquery-ujs --save 

And connect it to your template. I will not write the details here as I do, I have an assembly through Grunt and the connection of already assembled scripts. I hope you will not make this work;)

After connecting, you need to add a couple more lines to the header so that the library understands which token to send:
 <!DOCTYPE html> <html lang="ru"> <head> ... <meta name="csrf-token" content="{{.csrf_token}}"> <meta name="csrf-param" content="csrf_token"> ... </head> ... 


After that, it is worthwhile to include another filter support for Ajax (disabled by default). To do this, add the following to the /conf/app.conf file:
 csrf.ajax = true csrf.token.length = 64 

The second line here changes the length of the token, by default it is only 32 characters. The length can range from 32 to 512 characters.

If everything is connected correctly, then now you can make such secure links that will make the POST request method:
 <a href="{{url "App.Logout"}}" data-method="post"></a> 


I have it all. Thanks for attention!

Source: https://habr.com/ru/post/274457/


All Articles