Risk of using a persitent XSRF-TOKEN cookie in Angular - javascript

This is related to this question CSRF Protection for Refresh Token Cookie in SPA
I want to use the recommended XSRF-TOKEN cookie mechanism to protect another HttpOnly cookie. For this scenario I need to make the XSRF-TOKEN cookie persitent, because it has to be available at app start up after a reload. The default implementation in Angular $http looks up in session cookies only.
What are risks if I make the cookie persitent and manually set the X-XSRF-TOKEN HTTP header?

What are risks if I make the cookie persistent and manually set the
X-XSRF-TOKEN HTTP header?
The risk is that an attacker could eventually brute force the token value.
The recommendation is to have a new CSRF token per session. If you make this persistent then a malicious site could keep trying to submit a cross site request including a different token value each time. Eventually it will try every combination of token character and succeed in making the request.
Practically however, the user would have to visit the malicious website at the same time and every time. This can happen with browsers that remember the user's open tabs and automatically load each time.
You could also build in some brute force protection. For example, after 10 requests made with an invalid CSRF token you could abort the session and then inform the user that they have been logged out. This will mitigate the brute force attack, however this converts the attack into a Denial of Service attack as the malicious website will be successful at logging out the user. Therefore you should follow this up by contacting the user and informing them that a site that they are visiting is attempting to compromise them (you can check your server logs to determine the referer and origin headers).

If you choose to use Persistent cookies, you will be still vulnerable for CSRF attacks since the browser will send these cookies with the requests
For angularjs, the following is what i'm using in my SPA app; a CSRF token is generated by the backend server and passed as a header only in the request for the index.html file. from that point angular is configured to add the token in the header + in a session cookie - for each internal $http.post/delete/put/... requests
app.config(['$httpProvider', function ($httpProvider)
{
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
Test it
use this small snippet to manually test your api:
<!DOCTYPE html>
<html>
<head>
<script>
function csrf(id)
{
document.getElementById("csrf-form-" + id).submit();
}
</script>
</head>
<body>
<form method="POST" action="http://127.0.0.1:8080/api/test" enctype="text/plain" target="_blank" id="csrf-form-1">
<input name='{"protected":false, "ignore_me":"' value='test"}'type='hidden'>
</form>
<button onclick="csrf(1)"}>CSRF!</button>
</body>
</html>

A CSRF attack works on an unprotected site to which the user is logged in. Consider site S that uses session cookie C (and nothing else) to identify a user's session. This means that the browser will send C on every request to S. As the presence of the session cookie is all that's required to confirm a session, the user will be logged in when they access S. This is great. Exactly what we want.
Except...
Let's assume that S can is a website that can email cash via an URL such as https://S/email-cash?email=recipient#examplecom. An evil website E can have embed the link https://S/email-cash?email=ATTACKER#examplecom in one of its pages. Now, when the user is browsing site E while logged into site S and they click on this link, they'll end up emailing the attacker money. Even worse, this link can be executed in JavaScript behind the scenes so the user only needs to visit site E. Very bad.
The problem happens because every request accompanied by a valid session ID cookie C is treated as a valid request. The solution is to require the browser to send some piece of ID that it could only have gotten very recently from site S. This is the CSRF token. There's no way for the browser to get it unless it is given it by S and S will only give it when it's serving a page, not for a cross-site attack.
Now if you start storing the CSRF token as a persistent cookie, it defeats the entire purpose because it becomes something that the browser can send on a cross-site attack.

Related

Where do I store the refresh token and access token and how do I use it?

i can't easily decide how to receive the refresh token and access token from the back-end and where to store it.
the authentication process I understand is as follows.
XSS can be defended with cookies.
using cookies is vulnerable to CSRF.
however, in the case of cookie, it can be stolen as 'document.cookie'. So, use the 'httponly' option to prevent access from javascript.
cookie is always included in header when making http request, so it is vulnerable to CSRF. So, when logging in, 'refresh token' and 'access token' are created in the back-end, stored in the DB, and returned to the client.
request an api using an access token, and if it expires, update it using a refresh token.
as I refer to many articles, it is said that XSS is to be blocked with cookies and CSRF is to be protected with refresh tokens and access tokens.
and in the case of refresh token, it is stored in webStorage.
however, in order to prevent XSS, it seems that in the case of access tokens, cookies should be used to protect them (+ httponly applied), and in the case of refresh tokens, it seems that they should be stored in the client.
if the refresh token is sent in a cookie with the httponly option, isn't it accessible from the client?
in conclusion...
in the back-end server, should the access token be sent as a cookie and the refresh token included in the body?
Any ideas would be appreciated.
The tokens are usually sent back in the body of the response. This way your frontend app can easily read them and store wherever needed. Usually storing them in memory should be enough (in a variable or state of your app, etc.). When the user refreshes the page they will have to log in again, but that should not be a problem if the Authorization Server supports things like "remember me". If you're using an OpenID Connect-compliant Authorization Server, then you can perform a silent login - so obtain tokens without the need of redirecting the user anywhere.
If you store your tokens in a http-only cookie then your app will not have access to them, so you won't be able to call any APIs from your app. I think this is not what you're trying to achieve.
Keeping the tokens in memory could help you be a bit more safe from XSS attacks, but you will never be 100% secure. Have a look at this talk: https://pragmaticwebsecurity.com/talks/xssoauth.html where it is explained. In fact the only way to be sure that an XSS attack can't steal your tokens is to keep the tokens in a backend app, not in the browser.

CSRF - Is it safe to ask it with api call?

I'm using session based CSRF on a site using Angular. Is it safe to make an HTTP call to ask for the CSRF token?
For example, if I sent a request with valid user session to a page called /csrf/get and it prints a raw token, is this secure enough for CSRF functionality? If not, is there anything I can do to make it more secure while keeping the JSON retrieval functionality?
It will be the first api call before everything else and I will keep it on localstorage to use it on every http call
In short, no. The way that you are trying to do CSRF protection exposes you to CSRF since your csrf/get endpoint is not protected from CSRF.
Essentially, you need to protect yourself from two main attack vectors: XSS, and CSRF.
CSRF
CSRF involves your site and a malicious site that will attempt to make authenticated requests to your site. If there is a way to request a CSRF token from the malicious site, you are not protected.
Usual methods for protecting from CSRF are by returning a token from your authentication API call, and storing that token in the browser session. The problem with this method is that it opens you up to XSS.
XSS
Cross-Site scripting, or XSS vulnerabilities are related to external scripts running on your page. This includes potentially malicious scripts inserted by an attacker.
Local storage and session storage are not safe, so you shouldn't store a token in regular cookies, for example.
To be safe from XSS attacks Your authentication response can store cookies that javascript can't read by using HttpOnly cookies.
So, using a token that you store with javascript protects you from CSRF, but opens you up to XSS, where using a session cookie protects you from XSS, but opens you up to CSRF.
Protect your API from XSS and CSRF
The solution is to use both approaches: your authentication API should set an HttpOnly cookie to protect from XSS, and should return a token to protect from CSRF.
Note that there's no need for a csrf/get api since the token should be returned by the authentication method: you want to only send that token in exchange of valid credentials. Remember to also send and validate that same token on all authenticated API calls.
Here is a great article explaining API security, why and how to do it in much more detail:
http://www.redotheweb.com/2015/11/09/api-security.html
Note on login CSRF:
Logic forms should also be protected from CSRF by creating pre-sessions with CSRF tokens.
(from https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#login-csrf)
Most developers tend to ignore CSRF vulnerability on login forms as they assume that CSRF would not be applicable on login forms because user is not authenticated at that stage, however this assumption is not always true. CSRF vulnerabilities can still occur on login forms where the user is not authenticated, but the impact and risk is different.
For example, if an attacker uses CSRF to assume an authenticated identity of a target victim on a shopping website using the attacker's account, and the victim then enters their credit card information, an attacker may be able to purchase items using the victim's stored card details. For more information about login CSRF and other risks, see section 3 of this paper.
Login CSRF can be mitigated by creating pre-sessions (sessions before a user is authenticated) and including tokens in login form. You can use any of the techniques mentioned above to generate tokens. Remember that pre-sessions cannot be transitioned to real sessions once the user is authenticated - the session should be destroyed and a new one should be made to avoid session fixation attacks. This technique is described in Robust Defenses for Cross-Site Request Forgery section 4.1.
First of all, use https, http is unsafe.
Then, better not to use GET.
Safe way is to send token in successfull auth request's (POST) response.
For more info, check:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

Cookie without httpOnly, how insecure it is?

Im developing a web application which requires cookie to be set httpOnly = false.
Since, I find no other way to pass authentication cookies(for checking whether user has logged in successfully) from server side to be accessible via Javascript in my front end. This cookie is then used to send an AJAX request to my server side(added to the header). (Please do correct me if Im wrong and suggest me any other way)
My question:
How insecure is httpOnly = false? Is it safe enough with just forcing it to use cookieSecureOption = true so that it will always be send via HTTPS.
How can I protect it from XSS attack?
A "non-HttpOnly cookie" isn't a vulnerability in itself.
An "HttpOnly cookie" mitigates the risk of an XSS attack. That is, any attacker injected scripts into your website will not be able to grab the value of this cookie, thus protecting the session.
If your application requires the use of the cookie value to add as a header, then you cannot mark this cookie as "HttpOnly". You can change the request handler to look for the value in the cookie rather than in the header (so you can set the flag), however this may put your site at risk of CSRF. The most secure approach is for your handler to check authorisation via a "HttpOnly" cookie, and to use another token value in a header ("non-HttpOnly") to check for CSRF. If these values are different, e.g. in the encrypted token pattern or the synchronizer token pattern, then there isn't much value in attacker in only retrieving the one value via XSS because they can't use it to authorise requests. Note that any XSS vulnerability is usually a bigger problem than a CSRF vulnerability, because the attacker could always use their XSS attack in order to submit requests directly from your site, however it is a much harder attack to accomplish. At least with "HttpOnly" they cannot grab the auth cookies from your site in order to remotely login.
The other cookie flag you mentioned is the secure flag. This will limit the cookie scope to https connections only, and is recommended if you are using https (which is also recommended). This does not affect whether JavaScript can access the value though.
If you do use a "non-HttpOnly cookie" then you can still mitigate the threat of XSS as follows.
Move all script code into external js files and set a Content Security Policy to prevent any inline scripts from executing.
Make sure you are correctly encoding all user input when output (e.g. < becomes < in HTML) and run a web security scanner against your application.
If you do not have HTTPOnly flagged, your users are still more vulnerable to XSS than they otherwise would be, as the cookie can still be accessed from JavaScript. From your description, you should not need access to the variable from JavaScript, simply access the cookie from the server side (which is still possible with HTTPOnly flagged, cookies are sent with every request including AJAX calls) to retrieve authentication information. The Secure flag and HTTPOnly flag defend against completely different attacks.
There is a hybrid way of doing this. I say hybrid because it involves half of what your doing and a mix of what bksi mentioned in a comment.
Since I do not know your full scenario this answer assumes you are just looking for a way to authenticate the user before allowing them to make changes or start a process server side; login, viewing an account page, and so on. You should never rely solely on httpOnly = false I would recommend using it with what is below.
A Solid Solution
Set a normal cookie when a user logs in successfully, this does not need to be sent over HTTPS although it would be nice. This cookie should be a randomly generated token for their session. I usually hash (md5 encrypt in PHP) their user id (assuming you use a database) and a time stamp of when they logged in. This insures the token is unique.
Now that you have a token saved on their local machine as a cookie also make sure to save this token in a PHP session which is server side. Now any time they visit a page or an AJAX request is sent you can compare the local cookie to the PHP session value server side. This is the fastest way you can authenticate a user interacting with your server. If the values match they are legitimate.
Now this is not entirely secure. The local cookie can always be edited which is something we usually don't care to much about because this will only harm the user by invalidating their session. On the flip side a crafty hacker could alter the PHP sessions and that could invalidate other users because their session was erased or hijacked. A hacker would have to get a legitimate session token and make a cookie to match.
The Better Solution(s)
1) On the server side you could use a database instead of PHP sessions. The process remains the same but now you need to do a bit more work of keeping the sessions table in your database up to date. Usually this is done by saving the token with a time stamp and updating this time stamp every time the token is checked. If the token is checked and the last time stamp is really old (you decide how long that is) you can un-authenticate the user by destroying their local cookie and having them sign in again. This is more resource intensive though and can slow down sites with large traffic loads.
2) Use a form of double authentication. This would be using PHP session 90% of the time for simple things but when an extremely important process comes up, say updating personal information or providing credit card information, check with the database as well. This would require two different cookies to be saved on the users machine. One if for checking PHP session for authentication and the second is for checking the database. This scenario would be really hard for a hacker to break through to the more important things because they would need to figure out both tokens and the database one is not easy to steal.
Final Thoughts
This is a fairly secure answer but you should still implement extra security precautions. It seems you are misunderstanding how cookies work in general; your recent comment sounds like your using cookies and ajax backwards but maybe I'm misunderstanding. Here is how I do it:
[User]-> Tries logging in to website with a login form
[Server]-> Checks this information against the database Pass, log 'em in.
[Server]-> Generate and set a random token as a cookie
I use PHP here and usually store this cookie with a name like sessionToken. This cookie immediately exists now on the users computer and we, the server, always have access to it server side; we can call it up any time. This is not really secure though because people could copy the cookie without the person knowing/ steal it as we send it to them. I'll deal with that in a minute.
[Server]-> Create a PHP session (session id: abc123) server side that has this same token.
This is step one in security. PHP sessions are not as easy to steal or hack. So even if someone steals our users token cookie when they try to use it on their computer it will fail. Here is a vaild user:
[User]-> (PHP session id: abc123) Tries to access secured page or content. PHP session is called up and is checked against the cookie token. If they equal each other this attempt passes.
Here the user has a session on the server they don't know about that recognizes who they are and can be accessed only by the server; usually. It is here where your AJAX request come into play. Every time the user tries to do something that you want to see if they are even allowed to do, send a request via AJAX to a PHP script that authenticates the user. All it does is send back PASS or FAIL. Then you can use AJAX or Javascript to do whatever you need. Here is a hacker exmaple:
[Hacker]-> Steals a cookie from a user over a cafe's wifi.
[Hacker]-> Tries to access the website you are on with it.
[Server]-> (PHP session id: ???) Doesn't have one, destroy the cookie and ask this user (the hacker) to login again.
This is as much information and help I can give. Your latest comments are starting to sound like new questions you should post on Stackoverflow.

How can I secure my website from injections (Cookie editing)

I'm using cookies in my Java EE application (jQuery on the client) and while taking security as a key point, I came to know that one can read the cookies and edit them by reading article's. I'm really want to make application out of these attacks.
I read How to prevent Javascript injection attacks within user-generated HTML on SO and didn't find a solution to make my cookies secure.
There are several flags you can set for cookie to mitigate the security risk.
The secure flag. It mandates that cookie should only be sent through https. This is important, even when your site is using https. Why? Let's say a bank site forces end user to use https. The user connects to the bank site through https, login successfully. The bank site sends the cookie back to the user browser through https. Assuming a hacker can sniff the network and see all the cleartext communcation between the end user and the bank site. Obviously for now, the hacker cannot see anything, as the cookie is transmitted through secure channel. Here is what the hacker can do if the HttpOnly flag is not set
a) The hacker creates a site www.maliciouscode.com.
b) He sends an email to the end user with the link, luring the end user to the site.
c) The user takes the bait, connecting to http://www.maliciouscode.com site through another browser tab.
d) The malicious site redirects the user browser to the bank site through http.
e) The user browser sends the cookie through HTTP to the bank site.
f) The hacker intercepts the cookie since it is sent as cleartext, places it in his own browser and login as the user
The HttpOnly flag. The name is misleading. It is not the opposite of the secure flag. It means the cookie should only be used by browser through http (and https) protocol only, but not used by other means such as JavaScript. If a browser that supports HttpOnly detects a cookie containing the HttpOnly flag, and client side script code attempts to read the cookie, the browser returns an empty string as the result. This is to prevent the XSS attack.
Unless there is some other vulnerability in your site (or the user's system), there is no way for a third party to modify cookies.
Therefore you can treat them exactly the same as you would any other data that comes from the client (except that you don't need to worry about cookie data being faked with a CSRF attack). That is to say: Trust the cookie as much as you trust the user.
Cookies are not secure. Forget protecting them.
You should protect your server by having all communication on HTTPS. HTTPS protects your cookies more than anything else (it cannot protect against Session Hijacking though).
Do not store any sensitive information in the cookie other than the session id.
Make sure your cookies are configured as HTTP ONLY. If not, the session id will be sent as a part of the query string and can be intercepted (and cached) by any one.
Regenerate your session id on major events like user login, password change, etc.

Secure way to communicate OAuth token to javascript client

I am designing a multi-platform application at the moment (clients would include internally developed mobile apps, and an AJAX heavy javascript client initially) centred around a REST API. Since in the future the API may be open to third parties, I am looking at using OAuth 2.0 for authentication and authorization with the API.
I am trying to get my head around some of the security issues with this arrangement, particularly with regard to the javascript client. I don't want this client to behave like a third party client might, with a whole bunch of redirects and popups and stuff, which is what most OAuth documentation seems to focus on. Since it will be delivered from my own domain, I am thinking that the server side of the webapp can be the actual client, and store the client secrets and refresh tokens, while the javascript retrieves new auth tokens from the server as it needs them.
To put it in step by step form:
The user logs in using non-ajax html form, generating auth and refresh tokens which are stored server side. This sets a HTTP-only login session cookie.
The javascript client code is sent to the user's browser after login.
The javascript client makes a request to a resource that is part of its own application (not part of REST api) to retrieve the token. The session cookie ensures that the client is genuine, and the referer will also be checked. Auth token is returned.
The javascript client validates the token with the REST API.
The client can now use the token to make requests against the REST API until it expires.
If the auth token expires or the page is closed and re-opened, the javascript client can request a new token. The server side of the webapp takes care of refreshing the token and sends the new token, as long as the login session cookie is still valid.
Does this make sense, or would it leave massive holes in the system? In particular, is it insane to have a resource on the web that hands out authentication tokens based on a cookie being set?
Just make sure that any communication to browser is HTTPS, so that no one in the middle can steal your tokens. And set the "secure" flag on your auth cookies.
Most browser authorization schemes nowadays boil down to a session token that's passed in a cookie. The OAuth 2 scheme is a couple steps ahead because a) the tokens (can be) dumb tokens with no dangerous user info inside, and b) they expire.
(Just to put that comment in context: one time I popped open a session token from a site and discovered my home address and phone number was in there. Ack!)
I've seen code that does HMAC signing of requests inside the brower javascript, but it came with a huge disclaimer: don't use this in production. A signing scheme requires the client (javascript) to know a "secret" string, but the browser/javascript is so insecure that it amounts to handing your secret strings to the world.
But if you keep all your commuinication over HTTPS, then you're really just putting an OAuth twist on the familiar scheme of passing session tokens as cookies.

Categories