Cross-Site Request Forgery - Validate the value of the "Referer" header, and use a one-time-nonce for each submitted form - http-headers

The AppScan report insists that my site have some problems with Cross Site Request Forgery.
1-) Using token on forms is a good solution but in the report there are pages without forms like "Logout" page. It just kills the session and that's all, how can CSRF utilize there I don't understand.
2-) Checking "Referer" is a good solution? Everyone says no. And "Referer Header" is not always present.
3-) Same-Site Cookies is shown as the ultimate solution but I don't use cookies at all.
What needs to be done to mitigate CSRF?

Related

CSRF tokens - Do we need to use them in most cases?

So I essentially went on an epic voyage to figure out how to implement CSRF tokens. 20 years later - and now I feel like I just wasted my life. haha
So basically after making malicious test-clients and doing some re-reading it looks like it's virtually not a problem if:
1) You don't allow outdated browsers(they don't enforce CORS)
2) You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
3) You use a JSON API(all requests-responses is sending JSON).
4) You take care of XSS(they can inject code that will run from same origin ).
So as long as you take care of XSS(Reactjs! Holla) - all of the above(minus the old browser part I guess) is basically common practice and an out-of-the-box setup - so it seems like a waste of time to worry about csrf tokens.
Question:
So in order to avoid throwing my laptop under a moving car - is there any reason that I did all that work adding CSRF tokens if I am already adhering to the 4 prevention strategies mentioned above?
Just Fun Info - wanted to share one juicy find my tests came across:
The only ify thing I found with my tests is "GET" requests and an image tag
e.g.
<img src="http://localhost:8080/posts" onload={this.doTheHackerDance} />
The above will pass your cookie, and therefore access the endpoint successfully, but apparently since it is expecting an image - it returns nothing - so you don't get to do the hacker dance. :)
BUUUUT if that endpoint does other things besides return data like a good little "GET" request(like update data) - a hacker can still hit a "dab!" on ya (sorry for viral dance move reference).
tl;dr - Requiring JSON requests mitigates CSRF, as long as this is checked server-side using the content-type header.
Do we need to use them in most cases?
In most other cases, yes, although there are workarounds for AJAX requests.
You don't allow outdated browsers(they don't enforce CORS)
You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
CORS is not required to exploit a CSRF vulnerability.
If Bob has cookies stored for your site, CORS allows your site to allow other sites to read from it, using Bob's browser and cookies.
CORS weakens the Same Origin Policy - it does not add additional security.
The Same Origin Policy (generally - see below for caveat) does not prevent the request from being made to the server, it just stops the response being read.
The Same Origin Policy does not restrict non-Javascript requests in any way (e.g. POSTs made by <form> or <img> HTML directives).
Browsers that do not support CORS, also do not support AJAX cross-origin requests at all.
Therefore while not outputting CORS headers from your site is good for other reasons (other sites cannot access Bob's session), it is not enough to prevent CSRF.
You use a JSON API(all requests-responses is sending JSON).
Actually, if you are setting the content-type to application/json and verifying this server-side, you are mitigating CSRF (this is the caveat mentioned above).
Cross-origin AJAX requests can only use the following content-types:
application/x-www-form-urlencoded
multipart/form-data
text/plain
and these requests are the only ones that can be made using HTML (form tags or otherwise).
You take care of XSS(they can inject code that will run from same
origin ).
Definitely. XSS is almost always a worse vulnerability than CSRF. So if you're vulnerable to XSS you have other problems.
BUUUUT if that endpoint does other things besides return data like a
good little "GET" request(like update data) - a hacker can still hit a
"dab!" on ya (sorry for viral dance move reference).
This is why GET is designated as a safe method. It should not make changes to your application state. Either use POST as per the standard (recommended), or protect these GETs with CSRF tokens.
Please just follow OWASP's guidelines: "General Recommendation: Synchronizer Token Pattern". They know what they're doing.
CSRF counter-measures are not hard if you're using a framework. It's dead simple with Spring Security for example. If you're not using a security framework, you're screwing up big time. Keep it simple. Use one general method to protect against CSRF which you can use on many types of projects
CSRF is orthogonal to CORS . You are vulnerable even if you disallow CORS on your server and your users use the latest Chrome. You can CSRF with HTML forms and some JavaScript.
CSRF is orthogonal to XSS . You are vulnerable even if you have no XSS holes on your server and your users use the latest Chrome
CSRF can happen against JSON APIs. Rely on Adobe keeping Flash secure at your own peril
The new SAMESITE cookie attribute will help, but you need anti-CSRF tokens until then.
Keep reading

Why token-based authentication is better than cookie-based authentication in CORS/Cross-domain scenario?

I have seen in many places that one of the benefits of token-based authentication over cookie-based authentication is it is better suite for CORS/cross-domain scenario.
But why?
Here is a CORS scenario:
An HTML page served from http://domain-a.com makes an <img> src
request for http://domain-b.com/image.jpg.
Even if there's a token on my machine, how could the mere <img> tag know where to find and send it?
And according to here, it is suggested to store JWT as cookie, so how could that survive the CORS/cross-domain scenario?
ADD 1
Token-based authentication is easier to scale out than session-cookie one. See a related thread here: Stateless web application, an urban legend?
Just for clarification: Requests to any subdomain that you have are also considered as cross origin request (ex. you make request from www.example.com to api.example.com).
A simple <img> GET request to another origin is, indeed, cross origin request as well, but browsers are not using preflighted (OPTION) requests if you use GET, HEAD, POST requests only, and your Content-Type header is one of the followings:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Therefore simple <img> request to another origin won't have problem (regardless if subdomain or totally another domain), as it won't go through preflight, unless it requires credentials, because when you add Authorization header, the request needs to go through preflight.
About storing in localstorage vs in cookie: Localstorage has single origin policy, meaning you cannot access the data you have stored from the subdomain, ie, example.com cannot access data in localstorage of api.example.com. On the other hand, using cookies, you can define which subdomains can access to the cookie. So you can access your token in stored in cookie and send it to server with your requests. Cookies also doesn't allow to access data across different domains.
Hope this helps.

Security of https-login?

I'm writing an Apple iOS app that login to a account and fetching some balance. It use a plain html link for the login:
https://www.myaccount.com/login.jsp?username=myusername&password=mypassword
The username and password is dynamically loaded to the login link at runtime.
I've sniffed the traffic using Wireshark and I couldn't find the username or password in any of the packages being sent. I guess the SSL(?) thing of "https" have encrypted the query.
I'm I right? Is this a safe way? Any other thoughts? How should I handle the password in the app to avoid security issues? Is it cached? Do I need to encrypt it if I want the app to remember my password?
Although technically safe as Sjoerd pointed out, this is just great for social engineering. In the internet cafe: "Dammit, that's a cool article. Can you email me the URL real quick?"
You won't believe how many people fall for this kind of stuff.
Another drawback is that Browsers tend to cache URLs, so again very unsafe in situations where multiple people have access to the same machine.
A much better way is to use HTTP Basic Authentication or at least HTTP POSTing the data.
This is secure in the sense that it can not be sniffed, since the request is sent over an encrypted HTTPS channel. However, it does show up in the address bar of the browser and possibly in the log files of the server.
The safer way is to POST the username and password to the JSP page, so that they do not show up in the URL.

If I submit a form to a HTTPS URL from a HTTP URL, will the form data be encrypted?

I'm about to encrypt my website's login form and I was wondering if the user logging in needs to land on the login form at a HTTPS URL, or whether the form data can be posted to a HTTPS url from a HTTP url and still be encrypted?
Yes, the login data is encrypted, but there is no obvious way for the user to know this. It also leaves users open to a man-in-the-middle attack because an attacker could simply change where the form posts to.
For a site that really needs security, it is highly recommend that you require https on any login page.
Yes, it will be encrypted. The URL of the page from which the form is submitted doesn't matter, only the form target URL.
One thing to note, though, is that some browsers (IE 6, at least) will warn the user when submitting a secure form from an insecure page. Why that requires a warning and what the user is supposed to do about it, I have no idea, but it can confuse people (if they bother to read the warning).

Problem with web screenshots requiring authentication

I am making app that takes a screenshot of a URL requested by the user. I want to make it as transparent as possible when sites that require username and passwords are in question.
For instance, if user wants to screenshot its iGoogle page, he will send the server URL but, the screenshot will not be the same as what he sees on his screen.
Is there any way to do this ? I guess that in such cases I will have to actually request screenshot from the user. Perhaps user can even deliver me his cookie for that domain.
Any thoughts ?
Ty.
Yes, in most cases you'll need user's cookies.
If site uses regular cookies, you can create bookmarklet that reads document.cookie. This will not work with httpOnly cookies which are used increasingly often for sessions.
Some sites limit sessions to certain IP, and in that case you can't take screenshot without proxying request through user's computer.
If you can get user to use bookmarlet, an interesting trick would be to read and send DOM to your server:
image.src = 'http://example.com?source=' +
escape(document.documentElement.innerHTML);
For HTTP authentication easiest solution would be to ask user for login/password.