Cross-site request forgery token viewable in source code - ruby-on-rails

Should my Cross-site request forgery TOKEN be viewable on my web page source code
I am running a rails app in production and can see Cross-site request forgery token i am guess it should NOT be viewable

There's no way to put it on the web page without it being viewable. If you can't put it on the web page then you can't use it. There's no "secret" part of the web page which isn't in the source, or headers, both of which can easily be viewed. So, logically, if it is to have any function whatsoever, it must be viewable.
In order for it to function as part of a security system, therefore, the security of the system must NOT rely on nobody being able to see what the token is, and that is indeed the case. The security of the system depends on the token matching a stored value server-side: in other words, it means that the token provided with the form, ie sent from the server to the client, needs to match the one submitted BACK TO THE SERVER by the form.
Read this: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

Related

Forging a Cross Site Request Forgery (CSRF) token

I had a look at Rails' ActionController::RequestForgeryProtection module and couldn't find anything related to using secrets. Basically, it uses secure PRNG as a one time pad, xors, computes Base64 and embeds into HTML (form, tags). I agree that it is impossible for an attacker to guess what a PRNG generates, but nevertheless I can generate (or forge if you like) a similar token, embed it into my "evil" form and submit. As far as understand Rails compares ( verifies) it on the backend. But I can't fully understand why it is secure. After all, I can generate my own token exactly like Rails does. Could someone clarify how the security is achieved?
You might misunderstand what this protects against, so let's first clarify what CSRF is, and what it is not. Sorry if this is not the point of confusion, might still be helpful for others, and we will get to the point afterwards.
Let's say you have an application that allows you to say transfer money with a POST request (do something that "changes state"), and uses cookie-based sessions. (Note that this is not the only case csrf might be possible, but by far the most common.) This application receives the request and performs the action. As an attacker, I can set up another application on a different domain, and get a user to visit my rogue application. It does not even have to look similar to the real one, it can be completely different, just having a user visit my rogue domain is enough. I as the attacker can then send a post to the victim application's domain, to the exact url with all the necessary parameters so that money gets transferred (the action will be performed). The victim user need not even know if this happens in xhr from javascript - or I can just properly post a form, the user gets redirected, but the harm is done.
This is affected by a few things, but the point is that cross-origin requests are not prevented by the same origin policy, only the response will not be available to the other domain - but in this case when server state changes in the victim application (like money gets transferred), the attacker might not care much about the response itself. All this needs is that the victim user that visits the attacker's page while still being logged in to the victim application. Cookies will be sent with the request regardless of the page the request is sent from, the only thing that counts is the destination domain (well, unless samesite is set for the cookie, but that's a different story).
Ok, so how does Rails (and similar synchronizer token solutions) prevent this? If you lok at lines 318 and 322 in the source, the token received from the user is compared to the one already stored in the session. When a user logs in, a random token is generated and stored for that particular user, for that particular session. Subsequent requests that change state (everything apart from GET) check if the token received from the client is the same that's stored in the session. If you (or an attcker) generate and send a new one, that will be different and the request will fail validation. An attacker on their own website cannot guess the correct token to send, so the attack above becomes impossible. An attacker on a different origin also cannot read the token of a user, because that is prevented by the same origin policy (the attacker can send a GET request to the victim app, but cannot read the response).
So to clarify, CSRF is not a protection against parameter tampering, which might have caused your confusion. In your own requests, if you know the token, you can change the request in any way, send any parameter, the CSRF token does not protect against this. It is against the attack outlined above.
Note that the description above is only scratching the surface, there is a lot of depth to CSRF protection, and Rails too does a little more, with some other frameworks doing a lot more to protect against less likely attacks.

How to protect against CSRF

How can I protect my website against Cross-Site Request Forgery attack?
I am visiting a "normal" website. (f.e. normal.php)
In the background it loads another website (f.e. victim.php/send_comment) where I'm already logged in.
The website fills the comment boxes of the victim.php with JS and automatically send the request.
In the web I always find the trick to use tokens against CSRF. But in this example, the website normal.php will get the token, when it loads the other website.
Am I misunderstanding how the token works? If not, how can i prevent my site from accepting this request?
The whole idea of CSRF is that you can't get victim.php/send_comment without a token from a previous page you've visited.
You form a "chain" of requests from your initial login until you get there, where each request is authorized by the previous one - unless you intercept the login page, there should be no way to forge requests.
The easiest and safest way of doing this is just using a web framework that handles CSRF for you. Doing it by hand is probably unnecessary and error-prone.

Is it normal for my __RequestVerificationToken to be different with every request?

I've Google'd, but haven't been able to determine if ASP.NET MVC's v4 RequestVerificationToken should be different for every request?
I notice this in all environments, even when running on a single server. The user is logged in, but when refreshing the page (F5) a different token is generated every time.
Is this normal or not?
This is completely Normal. No difference when a user is logged in or not.
Note that: Synchronizer token pattern is a technique where a token, secret and unique for each request, is embedded by the web application in all HTML forms and verified on the server side. The token may be generated by any method that ensures unpredictability and uniqueness (e.g. using a hash chain of random seed). The attacker is thus unable to place a correct token in his requests to authenticate them

ASP.NET MVC ValidateAntiForgeryToken — can it be replaced with authorization check & referrer check?

In ASP.NET MVC there is a ValidateAntiForgeryToken attribute, that enables cross-site scripting defence.
Is it possible to replace this mechanism with
authorization check, including checking that resource, that is being manipulated, belongs to current user;
referrer check, that will forbid AJAX web api requests from external hosts;
inhibition of site hosted in iframe?
This does not prevent cross site scripting, only cross site request forgery.
authorization check, including checking that resource, that is being manipulated, belongs to current user;
No, because the resource does belong to the current user, it is only the request that has not been willingly made by the current user.
e.g. say on your website www.foo.com you have the following URL that will delete the user's account.
www.foo.com/DeleteAccount
Your user is logged into www.foo.com. Now say your user visits www.evil.com which includes the following image tag on the page.
<img src="http://www.foo.com/DeleteAccount" />
This will make a request to your page and delete the user's account because the DeleteAccount resource will have checked authorisation via cookies and determined that the user is indeed authorised because the auth cookie was supplied with the request.
referrer check, that will forbid AJAX web api requests from external hosts;
Yes, this is a valid check although it is weaker than the method of using the Anti Forgery Token as mentioned in your question.
The OWASP CSRF Cheat Sheet states
Although it is trivial to spoof the referer header on your own browser, it is impossible to do so in a CSRF attack. Checking the referer is a commonly used method of preventing CSRF on embedded network devices because it does not require a per-user state. This makes a referer a useful method of CSRF prevention when memory is scarce. This method of CSRF mitigation is also commonly used with unauthenticated requests, such as requests made prior to establishing a session state which is required to keep track of a synchronization token.
However, checking the referer is considered to be a weaker from of CSRF protection. For example, open redirect vulnerabilities can be used to exploit GET-based requests that are protected with a referer check. It should be noted that GET requests should never incur a state change as this is a violation of the HTTP specification.
There are also common implementation mistakes with referer checks. For example if the CSRF attack originates from an HTTPS domain then the referer will be omitted. In this case the lack of a referer should be considered to be an attack when the request is performing a state change. Also note that the attacker has limited influence over the referer. For example, if the victim's domain is "site.com" then an attacker have the CSRF exploit originate from "site.com.attacker.com" which may fool a broken referer check implementation. XSS can be used to bypass a referer check.
Also note that sometimes the referer isn't always passed as the user may be using privacy software that removes the header.
inhibition of site hosted in iframe?
This can be a valid defence for widgets that you host to be included on other sites.
e.g. www.bar.com could include your widget on their page via the use of a script tag:
<script src="//www.foo.com/widget.js"></script>
In order to prevent www.bar.com from submitting the form within your widget, your JavaScript code would document.write an IFrame into the page and then include your content within that. The Same Origin Policy will prevent the IFrame content from being read by the parent page and your form could not then be submitted by the site that includes your widget. However, here you may need a manual confirmation window to pop up in the case of any clicks to prevent click jacking attacks (e.g. if you had a like button (similar to Facebook) and you wanted to prevent fake likes from the including page submitting your form automatically).
OWASP Recommendation
The OWASP Recommendation is to use the Synchronizer Token Pattern which is the one implemented by ASP.NET MVC with ValidateAntiForgeryToken.

Is it safe to disable CSRF-protection for an authenticated POST endpoint in Rails?

I'm finding myself in a situation where I could provide a much nicer user experience if I could disable CSRF token checking for an endpoint in my rails app.
The endpoint is a create action (routed to by POST /whatever), that's behind a devise :authenticate! filter.
Would I open myself up to any additional security risks by disabling the CSRF-protection for that specific endpoint, or can I safely rely on the authentication before_filter to stop the kind of malicious requests that the CSRF token protects against?
Following is a bit more detailed explanation as to why I want to do this if anyone is interested.
My use case is that I basically want to create something very similar to the Facebook likebutton, but this button (unlike the Facebook counterpart) is commonly going to occur multiple times on the same page.
The CSRF protection works fine except for the case where the user visits the page with empty cookies.
In this case rails generates a new session for each of the X number of requests since they are all cookie-less. And, of course, for each new session a new CSRF token is generated and returned in the response to the iframe.
Since the browser only keeps one cookie for the domain, any subsequent requests from each of the iframes will be mapped to the same session, and thus all of the CSRF tokens (except one) are invalid.
The mapping to a single session is nice since the user can be prompted to log in once, and then be mapped to the same log in for each of the subsequent buttons presses – without having to reload the page.
A compromise would be to respond with a 401 Unauthorized, but preserve the session of the rejected request (by overriding handle_unverified_request). This would trigger the sign in popup again, but this time an instant redirect occurs since the user is already signed in.
It would, of course, be best to avoid that flash of the sign in popup window, and thus I'd like to disable the CSRF protection all together for just the create action.
Authenticated requests are precisely what CSRF is about.
What CSRF means is that the attacker convinces the user's browser to make a request. For example you visit a page hosted by an attacker that has a form that looks like
<form action="http://www.yourapp.com/some_action">
#for parameters here
</action>
And some javascript on the page that auto submits the form. If the user is already logged in to your app, then this request will pass any cookie based authentication checks. However the attacker doesn't know the csrf token.
For an unauthenticated request, csrf serves no purpose - the attacker can just go ahead and make the request anyway - they don't need to hijack the victim's credentials.
So, short version: disabling csrf protection will leave you vulnerable to csrf style attacks.
What CSRF is really about is making sure the form contains a parameter that an attacker can't fake. The session is an easy place to store such a value but I imagine you could come up with alternatives. For example if the user can't control any of the parameters in the form, you could add another parameter which would be a signature of all the other parameters in the form (possibly with some sort of timestamp or nonce to prevent replay attacks). Upon receiving the request you can tell whether the request is from a form you generated by verifying the signature.
Be very careful about this sort of stuff as it is easy to get wrong (and even the big boys get it wrong sometimes.

Resources