7

I've read multiple topics about web-specific attacks and preventions, but I'm still not sure if I got the point.

Let's imagine that we have a website (myapp.com) and a web service (myapi.com). The webapp and the service exchange data using JSON.

The service

The service has some restricted operations. To access any of these, the user has to log in using a username/password pair. (The passwords are hashed before they are stored in the database.) When a login request is valid, a random-generated token is sent back to the caller and its hashed version is stored in the database with the id of the logged in user. (The random token generation has to be strong so it cannot be guessed.) Each time a restricted operation needs to be accessed, a specific header must be set to the token above and it must be sent by the caller. This way the service can verify if a/which user is logged in (by hashing the token and searching for a database entity).

The website/webapp

When a valid login request is POSTed to the service, the received token is stored in the session. Each time the client (the browser) wants to access a restricted page, the app checks if the token is available or not (and redirects to the login page if the token is not found). Then it sends every request to the service with setting the required header to the token stored in the session.

The CSRF attack

There is an evil site (evil.com) that wants to (for example) modify the victim's password. There are 3 different communication line possible:

evil.com -> myapp.com

GET/POST: Both requests seem to be okay since the myapp.com requires a cookie with a session id to be able to read the token from the session. And because it is not provided by the evil.com, it will be redirected to the login page. (The evil.com can provide a session id but first, it has to manage to acquire someone else's id.)

evil.com -> myapi.com

GET/POST: Both requests seem to be okay since the web service requires a header containing a valid token. (Same as before, the evil.com can send a valid token in the header but first, it has to acquire one.)

evil.com -> victim

GET: Basically it seems to be okay. Even if the evil.com manages to create a GET request to the myapp.com through the victim, nothing will happen (besides that the victim will receive a HTML page)

POST: This is the real danger here (as far as I understand) because the evil.com can send a POST request through the victim's browser (e.g. by automatically submitting a form with hidden inputs) which sends the cookies (including session id) with the request, so the myapp.com sets the user's token to the header and finally, the service executes the action.

I've made a beautiful (just kidding) diagram about this:

csrf connections

How to prevent the CSRF attack

I'm planning to check the origin/referrer headers if they are present. If a request comes from a completely different site it can be rejected without checking anything else. But as far as I know, these headers are not always present. That's why we have to make some sort of verification. Or what is the downside of the origin check?

When the myapp.com generates the HTML view which contains a form, it also adds a hidden input with the value of the token stored in the session. This way when a POST request is received by the myapp.com it can verify that the hidden input is available or not and it can also compare its value to the value stored in the session. And since evil.com cannot read the victim's cookie, it cannot guess the required hidden field.

What about AJAX?

Is there anything else?

Since I'm just scratching the surface of the web security world, I'm not sure if there is anything else that can cause problems here. For example is there any additional header that can be useful to secure the application? What about older browsers that do not support some of the proposed solutions? It would be the best if you could provide me some examples (and preferably solutions or keywords) that can break through this defense.

As a side note: I'm interested (and have some experience) in php, Java (JSP, Servlet) and C# (ASP.NET). These might (and possibly) have different level of security built-in. I know that there are multiple trusted frameworks but my point is to learn about these things and not just have a "drop and it works" solution.

Related posts:

csisy
  • 171
  • 3
  • 1
    The best way is to have a token that needs to be passed explicitly... unlike cookies which are passed implicitly. – mroman Nov 10 '17 at 17:39
  • why would the origin/referrer headers be missing? – dandavis Nov 10 '17 at 18:57
  • @dandavis I'm not sure if it can be missing or not but according to [this](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Checking_the_Origin_Header) it is very rare. However if we can identify the request based on the origin/referrer, why do we need token-based checks? – csisy Nov 10 '17 at 20:12
  • 1
    tokens are backwards compatible. if you only care about useragents from the last 5 years, and deny all missing-header requests up-front, your token validation routine would never find a failure. Programming-wise, if a calculation is constant, it can be hard-coded instead. – dandavis Nov 10 '17 at 20:22

1 Answers1

2

As pointed before in comment, the OWASP website have a full list of protection methods to protect against CSRF attacks.

My preferred method is to do requests with AJAX (XHR/Fetch) that permit custom header and checking on the server side that the custom header exists, but it's opinion based.

lakano
  • 157
  • 9