CSRF (cross site request forgery) attacks exploit the property of web browsers where in they automatically include any cookies set by a given domain, in any web request (regardless of origin) sent to that domain. CSRF attack is also called XSRF and session riding. It involves a hacker tricking a user into clicking on a link or form submit button(on a different site ! ) that changes some state on the target system . Essentially the attacker injects a network request to the genuine website via the browser where the user is logged in.

Prerequisite topics and nuances for understanding CSRF 

What is a cross origin request

If a web application running under one domain tries to access resources in another domain then it is called a cross origin request.

How an attacker can create a CSRF attack with HTML form against a POST end point.

How an attacker can create CSRF attack with script against POST end point and attack mitigation

Steps for CSRF attack with script against post endpoint

Attack mitigation: Here is what can be done to make a post endpoint ajax only and protect it against CSRF.

How an attacker can create CSRF attack against get end point.

Should get requests change state and should get end points be protected against a CSRF attack?

Preventing CSRF attacks via header verification.

Origin header and referer header (part of all requests) tell where a request originated from. Both these headers should be checked to ensure that the value of these headers is the same as trusted origins. This method can be used for CSRF checks for unauthenticated requests also. Typically both headers should be checked. Note that both these headers cannot be programmatically modified via javascript. While tools like burp proxy can intercept the request to change this header, in the case of CSRF, the attacker does NOT have the capability to intercept the request made from the actual user's browser. When verifying these headers against a target origin, the target origin could be configured on the server side, or determined based on host header value (or X-Forwarded-Host header). There are some more nuances that are covered in this article. https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#identifying-the-target-origin .

Header verification can protect from CSRF attacks from subdomains also. Read more about nuances of referer header here https://seclab.stanford.edu/websec/csrf/csrf.pdf  .

Same-Site Cookie Attribute to Prevent CSRF Attacks

Same-Site Cookie Attribute helps in controlling if cross-site HTTP requests(ajax / normal browser request) (eg request from b.com to a.com ) go with cookies.  In other words with the help of Same-Site cookie attribute, developers can now control whether cookies are sent along with the request initiated by third-party websites. If the request is not cross site, the value of same site attribute does not matter. Read more https://clarifyforme.com/posts/5678598534987776/HTTP-Cookies

Note that Samesite attribute should be used as an additional layer of defense.

Using Custom request headers to prevent CSRF Attacks

Using CSRF tokens to prevent CSRF Attacks

How to ensure that a form can only be submitted from my own website? CSRF token can help here. A CSRF token is a random, low collision(odds of two identical tokens being generated by the algorithm are extremely rare)  string. When the server is generating a form it wants to protect from CSRF, the server would generate the CSRF token, add it to the form as a hidden field and also store it in the session. (The CSRF token could be generated per session also)  Now the form would look like this:

    <form action="https://icicbank.com/debit" method="POST">

      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">

      <input type="text" name="fromAccountId">

       <input type="text" name="amount">

      <input type="submit">

    </form> 

 

When the user submits the form, the server simply has to compare the value of the posted hidden field csrf-token with the CSRF token stored in the session object.  Note that copying the static form from an authentic page to a different website would be useless because the value of the hidden field changes every time the form is generated (or per session). ie on submit of copied the html form, the copied hidden field value will not match the value in user session on the server. Note that generally protecting all post requests is important as through CSRF attack, the attacker typically triggers a state change, not read data. 

Note that if you want to avoid storing the CSRF token in the session object (to keep the session object light weight?)

Note that the CSRF token in the above discussion is sent downstream in a hidden form field. 

Note that the CSRF token can be sent downstream in

CSRF token can be sent upstream in

Additionally CSRF token will protect from CSRF attack from subdomain also which samesite cookies will not help.

Double submit cookie

Double submit cookie is used when we want to keep the server-side code stateless. In this approach, the CSRF token is sent both in a cookie and form body in a hidden field. On form submit, the server will compare the cookie value with the hidden field value received as a request parameter. Note that both the values being compared on server have come from client in this approach. One is a hidden form field and other is a cookie. Note that if attacker.com is trying to attack example.com then the attacker can create a from with hidden field with value csrfrandomtok1, but he cannot create a cookie which will go to the domain example.com

Let us say the site being attacked is example.com. Now if

Angular JS mechanism for blocking CSRF

AngularJS provides a mechanism to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (by default X-XSRF-TOKEN). Since only JavaScript that runs on your domain could read the cookie, your server can be assured that the XHR came from JavaScript running on your domain. Read more  https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection 

CSRF in login form

Even though CSRF is called a session-riding attack, ie an attack using an already established session, yet CSRF attack is possible against login form(before the user logs in). The difference is that

Paypal and google had this vulnerability. In a login CSRF attack, the attacker forges a login request to an honest site using the attacker’s username and password at that site. If the attack succeeds then all operations done by the user on the browser will affect the attacker's account

Here are the steps of login CSRF.

Attack mitigation can be done using the following techniques

Please note:  Check StackOverflow questions like this where the wrong explanation has become a top answer https://stackoverflow.com/questions/15602473/is-csrf-protection-necessary-on-a-sign-up-form 

User interaction based CSRF prevention

Note that these spoil user experience hence should be used where there are strong security implications.

Cross site websocket hijacking

during a websocket handshake to switch from http to ws the webscoket protocol doesn't prescribe any particular way that servers can authenticate clients. If cookie based mechanism is used then cross site website hijacking can happen. Because WebSockets are not restrained by the same-origin policy, an attacker can easily initiate a WebSocket request (i.e. the handshake/upgrade process) from a malicious webpage targeting the ws:// or wss:// endpoint URL of the attacked application. Due to the fact that this request is a regular HTTP(S) request, browsers send the cookies and HTTP-Authentication headers along, even cross-site. In the WebSocket scenario this attack can be extended from a write-only CSRF attack to a full read/write communication with a WebSocket service by physically establishing a new WebSocket connection with the service under the same authentication data as the victim. Note that Origin header is sent along the WebSocket handshake/upgrade request. This is like in a regular CORS request utilizing Cross-Origin Resource Sharing: If this was a regular HTTP(S) CORS request, the browser would not let the JavaScript on the malicious webpage see the response, when the server does not explicitly allow it (via a matching Access-Control-Allow-Origin response header). How ever this protection is not there for websocket. The developers should check the origin header and block the request themselves.

Test yourself 

Question > Is CSRF protection required for GET requests?

Question > Can CSRF be used to read data?

Question > Is CSRF protection (say thorough CSRF token) required when SameSite is set to Lax(which is the default).

Question > If samesite cookie attribute is there, why do we need CSRF token?

Question > Is CSRF protection required in login page where no user session is established?

Question > A website target.com has not specified the same site attribute of the session cookie and hence it defaults to lax. It has a post end point which is not protected against CSRF . Can example.com launch CSRF attack via ajax? Can example.com launch CSRF attack via form post? Can subdomain.target.com launch CSRF attack via ajax? Can subdomain.target.com launch CSRF attack via form post.

Click on pitfalls icon on rhs of this post and go to gotchas section to see answers.