in a double-submitted cookie csrf prevention scheme, is it necessary for the server to provide the cookie?
it seems i could have javascript on the clients page generate and set a cookie "anti_csrf", then double submit that (once as a cookie, done by the browser, and once in the body of the request).
a foreign domain would not be able to read or write the "anti_csrf" cookie to include it in the body of a request.
is this secure, or am i overlooking something?
Tgr, read this:
http://jazzy.id.au/default/2010/09/20/cracking_random_number_generators_part_1.html
All the attacker needs is to get a token or two out of the random number generator, and then they can predict every subsequent and every previous random number if it's not cryptographically secure. If the random number generation is done client side in Javascript, I don't know of a single browser that uses a cryptographically secure random number generator, so they simply have to call Math.random() a few times and they can work out what token was generated for your cookie.
If the user already has the "anti_csrf" cookie set for your domain, then the CSRF attacker is home free! The HTTP request will go out with the cookie, and of course it's easy to include the parameter in the POST if you know what the value is.
The cookie name doesn't have to be a secret, but the cookie value has to be a hard-to-guess secret known only to the user session. That way, the attacker does not know (and cannot guess) what to put in an attacking HTTP transaction.
If you put the code on the page that makes up the cookie value, then you have to assume that the attacker can get his/her own session at your site (that is, a valid "real" login) and examine the code directly. If it's easy to figure out how the cookie value is generated client-side (and, for just about any client-side solution known to man, it will be), then again the attacker can have their attacking page include the right parameter value in an attack POST.
On the first glance it seems safe, but it will mean users without javascript cannot use your forms.
Related
I am setting http-only cookie from the server for storing some user info so that i can validate user on backend. Say some hacker steals this cookie from someone's browser and go to my webpage and add the same cookie using document.cookie = "cookie_name = cookie_value" if cookie is not there. If cookie is there then he can delete the existing http-only cookie using chrome developer tool and later add it using document.cookie = "cookie_name = cookie_value" on his browser.
Now when server gets a call from hacker browser, it gets a cookie set by hacker and would validate it. How can i stop this?
Cookies leave you vulnerable to Cross-Site Request Forgeries and their kin. Not just hackers stealing cookies, but hackers borrowing a user's browser which already has the cookies. This is part of why tokens are more common today.
If you have to use cookies, there are various things you can do to make them slightly less insecure--updating the cookie on each request, verifying request IP against sending IP, configuring your web pages not to allow the loading off offsite content, forcing re-login for any major actions, and other user verification means. None of them is perfect.
Simple: You cannot. http-only serves a different purpose than validation. Your assumption that a hacker will use a browser is the first problem you have. I would never use a browser for something like that since a browser would restrict me. I would forge a HTTP request with my own tools and send a header with http-only and secure and whatever you want me to to your server.
If you want to validate your cookies, you will need to implement your own solution instead of relying on browser mechanisms. You could for example bind the cookie to a certain IP range and add some kind of token to the end of the cookie-key or cookie-value.
In general, do what #bryanx says. DO NOT USE COOKIES TO STORE DATA. They are fine for session tokens and the like.
Don't use cookies.
Cookies are necessary for preserving information between sessions, but any time you leave information on the client, you open yourself up to potential issues like you described. If you only need the information maintained during the user's session, you may want to consider using a $_SESSION instead of a cookie.
If you must use cookies, you may want to consider building out logic that if the cookie doesn't match a previously authenticated device, that you challenge the user again for their credentials. There are many ways to solve for this, just get creative.
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.
We're developing a system using AngularJS and PHP. I have some concerns about the security on the matter of authentication. I wrote a basic authentication based upon multiple different examples around the web (I only started learning Angular), which uses a database via REST API calls. On some routes it checks if the user information exists before it creates a promise, but I have a few questions:
Can session information be stored in$window.sessionStorage or $cookieStorage without the client being able to modify these values or should I keep them server-side with PHP $_SESSION and fetch them from there, never storing them anywhere in JS? Session information can contain uid, role, email and name
Can I store a value, like let's say $rootScope.role or $scope.role without the client being able to modify this value? Let's say for example we have multiple levels of user accounts where super-admin is the highest. If I create a route with a resolve which would check the $rootScope.rolelevel, can a novice go change the $rootScope.role value to super-admin gaining access to restricted backend sections?
Will I have to implement a GET /session check on every route to which gets $_SESSION data to actually make sure this data stays untouched?
Or am I just paranoid?
You're not paranoid, any client-side authentication should be questioned. When it comes to security, you can't assume that the client is forbidden or unable to do anything on their own device.
Security related functions must stay on the backend, an environment you set up and control.
can a novice go change the $rootScope.role value to super-admin gaining access to restricted backend sections?
Asking questions like "can a novice..." are futile in my opinion. Do you only want security against novice malicious users? If your "restricted backend sections" can be accessed by modifying the frontend, you're doing something wrong.
Great question! Front end security requires the cooperation of the browser and your server.
Javascript is an untrusted environment, so you can’t reliably enforce any authorization there (i.e. you can’t use properties on $scope to prevent a user from doing something). Your server needs to enforce these rules by ensuring that every API request is properly authenticated and authorized.
API requests are typically authenticated with a cookie. The cookie typically contains a session identifier, which points to a row in your database which contains the authorization information (i.e. what the user is allowed to access). The user can get this cookie by logging in (presenting hard credentials like a username and password).
The cookie may also contain a signed access token, such as a JWT. Depending on your architecture you can remove the session database and rely purely on the signed token for authentication.
In either case you want to set the HttpOnly flag on the cookie when your server is sending the cookie to the browser. This will prevent the JavaScript environment from reading the cookie, this is a good security measure to yourself against XSS attacks.
You also need to protect yourself against CSRF attacks. This is a situation where another website can trigger a GET or POST request to your API, and this will send along the authentication cookies. You can guard against this by creating another cookie that does NOT have the HttpOnly flag, and storing a random value in it. The JS environment must attach this value to any request, typically as a custom HTTP header. Your server then asserts that the value is associated with the session or token.
I’ve tried to cover all the bases in this answer. If you’d like to read more, you can check out these blog posts that I’ve written, they discuss token authentication, but each has sections that cover front-end security issues:
Token Based Authentication for Single Page Apps (SPAs)
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts/
Disclaimer: I work at Stormpath and we provide a secure, hosted user management solution for any application, including Angular! See https://docs.stormpath.com to learn more and find the SDK for your server.
I am trying to create a secure way for users to log in to and perform certain authorized actions on my custom website. I am trying to have good security without the use of SSL.
At login now, this is what I am trying to improve:
User types in credentials (e-mail and password)
Client browser (JavaScript) one-way-hashes password with SHA-512, sends credential as login-request
Java-based backend receives request, further encrypts the received password-hash(with salt etc) to fit the hashing in the database (which was created on registration), checks for match, and returns a cookie containing a fresh token.
Backend also connects token to user in the database, and the backend will therefore know who future requests is coming from based on this token (without ever sending credentials in the request)
The idea is that if someone manages to pick up such a cookie (or the initial request), it's impossible to get the user's password.
This is great and all, but there's still the problem with repeat-attacks and man-in-the-middle-attacks, when 'bad guys' pick up a request, and uses the token to do stuff on another user's behalf.
By reading up on how to prevent this from happening, I have found that an acceptable method of preventing this could be adding a 'counter' to the token in the cookie, to show how many times the token has been used.
Let's say the cookie initially contains a token and a counter of 0, like this cookie-content: "abc123:0", where the token is abc123, and the counter is 0. It's suggested that the client increment the counter every time a request is made. Let's say a user wants to send a chat-message to another user. The cookie attached to this request will then contain "abc123:1". The backend stores the counter as well as the token, and checks both values. If the received counter is more than the stored counter, awesome. If a 'bad guy' picks up the requests and try to repeat it, the counter will still be 1, and the server will reject it, as the stored counter also is 1(or more).
This sounds great, but I'm not sure how this is any more secure? The 'bad guy' can simply edit the counter-value in the cookie to be 99999 and succeed?
I figured the content of the cookie (the token and the counter) should be hashed in some way, so that the content isn't plain-text. However, the client is HTML/JavaScript; the 'bad guy' can simply check which encryption-method is used, and decrypt it. All scripts are public.
I read something about improving this by sending a one-time 'secret' from the server to the client before the request is made, but I don't see how I can implement this. I guess, on requesting www.example.com/chat, I could generate a random 'secret', and send this to the client, and the client can add this to the cookie when sending a chat-message, or use it as a key, so that an encryption would be more secure, but how would the server know the secret upon receiving the request? How can the server reverse this? The server has to know the secret when decrypting it, so where should it be stored? Plain-text in the cookie next to the hash? Then the 'bad guy' can do the same thing. In the database? Upon requesting www.example.com/chat, should the backend know WHO is requesting it, so that it can be stored in the database along with that user? In that case, how should the backend authenticate the user, to be sure that there's not a man-in-the-middle or repeat-attack requesting /chat?
What is this method of security called, and is it possible to use it for what I need (with HTML/JavaScript)? If not, what are my options, beside SSL?
It's called bad security that does not rely on trust.
The client needs to fully trust the server, otherwise everything - including the page that is used to enter the password - cannot be trusted. Currently the only way of establishing trust is the certificate store that is provided within the browser (you should be able to trust the browser!). And the only software that is able to use it across browsers is SSL/TLS.
Is there anyway to access the data associated with a cookie such as path, flags, and expiration date from javascript? All I've been able to find for cookie access is document.cookie, which only provides a list of name value pairs. Why is the interface for cookie access so limited?
No, there is none, in terms of safe, cross-browser support.
Reasoning comes down to security.
The goal of cookies was to allow for communication back and forth from the browser to the server.
If you could allow any front-end script to manually edit the domain / path / expiration of a cookie, just for knowing its name, it would lead to a lot of potential security-holes, if not for spoofing access, then at least for invisibly tracking people.
That's not to say that cookies are inherently safe, or even particularly safe at all.
I mean to say that by allowing any and all JS to edit any and all cookie data sent to the server (moreso than just CRUD), any pretence of security would disappear in a heartbeat.