I'm loving using ServiceStack, but one question has come up from a colleague that I cannot answer. The Authentication mechanism sets a ss-pid and an ss-id cookie, which is explained here: https://github.com/ServiceStack/ServiceStack/wiki/Sessions
When trying to access a restricted resource, these cookies need to be provided, otherwise you'll receive a 401 Not Authorized result.
My question is this. Why use a cookie rather than a custom HTTP header value that includes the sessionId or equivalent cookie values? Is it because the cookie inherently has its own mechanism to maintain expiration? What were the design decisions undelying the use of cookies over HTTP headers?
HTTP Cookies are inherently sticky and is the most appropriate way for maintaining sessions over HTTP. After the server instructs the client to add a Cookie, every subsequent request that the client makes back to the same server will also retain that cookie - this what enables the Client/Server session.
Related
The following talk https://youtu.be/67mezK3NzpU?t=2408 at 40:08min, Hubert mentions that the best way to prevent a CSRF attack is to do the following:
Generate a random id server side - lets call this the CSRF id.
Add this id to your jwt cookie. Also add a response header with the id (e.g. csrfId: xxx)
Have the client save the id to local storage.
On each request, the client should append a header with this id.
On each request, the server should verify that the id in the received cookie matches the one in the received header.
My question is: what would stop the CSRF attacker reading the cookie manually, getting the ID and then adding that to the attack request?
Also, wont localstorage leave the ID vulnerable to a XSS + CSRF combination attack? (I'm not sure this is possible)?
what would stop the CSRF attacker reading the cookie manually, getting the ID and then adding that to the attack request?
Setting the cookie attribute HttpOnly makes it inaccessible to Javascript. Using a custom request header prevents an attacker from adding the ID to the attack request:
«This defense relies on the same-origin policy (SOP) restriction that only JavaScript can be used to add a custom header, and only within its origin. By default, browsers do not allow JavaScript to make cross origin requests with custom headers.» -https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers
Also, wont localstorage leave the ID vulnerable to a XSS + CSRF combination attack? (I'm not sure this is possible)?
CSRF protection can be bypassed if you have a XSS vulnerability, regardless of using localstorage.
However, OWASP explicitly recommends not storing the CSRF token in cookies or local storage.
So I think your question is warranted, and I don't understand how that can be the best way to prevent a CSRF attack.
If I may, I recommend you check out the OWASP CSRF prevention cheatsheet if you haven't seen it already.
Now authorization sheme looks like this:
If the user input the correct data, the server generates a unique sessionKey, inserts it into the session table with FK for this user. In response to a JSON request, I send this sessionKey. The web client sets this key it in a cookie.
But the problem is that if the web client stores this cookie, JS will have access to them, and it is not safe.
The alternative is to set the HTTP-Only cookie. But it is not clear whether it is necessary to use CSRF middleware in this case. Does the HTTPOnly attribute solve the problem of XSS / CSRF attacks? If it does not decide and you need a CSRF middleware, then the csrf cookie must be a session cookie.
The problem is that all the csrf middlewares for my framework do not allow to use of the session csrf cookie. Alternatively, write my own middleware.
Do I understand correctly that the csrf middleware stores the token that I gave to the client in RAM and verifies on every request? But then what's the point of this token if it can be intercepted in the same way as an authorization cookie?
Let's start with stating that Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF) are two different animals.
XSS is about embedding malicious code into a site to have it executed on the client machine. No HTTPOnly flag can mitigate this.
CSRF is about embedding malicious code on some third party site and sending you the link to the third party site. The malicious code can try to fire GET/POST request (which can bypass browsers Same Origin Policy) and execute some unwanted actions on the site the user is logged to. It's easier to understand this with an example:
You are logged into your site on https://example.com. You are authenticated with a cookie.
Someone sends you a link to https://malicious.net. You open the link in a separate browser tab.
Malicious code is being executed and fires a request to https://example.com/deleteAccount=1. Cookie will be attached, request will be authenticated and executed.
The answer is no - the HTTPOnly flag will not mitigate any of this. But let us concentrate on solving CSRF issue. What options do you have?
In fact you have many: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
IMO the easiest could be passing the sessionKey not over a cookie, but over an Authorization header. This can not be done automatically by the browser so you would be safe from CSRF attacks.
Say I login through an opendID connect provider and am redirected to my callback www.mysite.com/auth/callback. I then create an httponly cookie, which contains an id referencing to my received tokens, that is passed to the browser at wwww.mysite.com/. How would another site submit a request that contains that same session cookie? Does the browser not pass only the cookies of the requesting domain. So if www.evil.com tries to make a request to www.mysite.com/api/endpoint, won't the session cookie not be passed, making the forged request invalid?
Am I missing something basic here??
When web browsers send a request to a different domain, they're nice enough to first check if they already have cookies for that domain, and if they do, then they send them along with the request. So, if you're on a web application trying to send a request to your app, it'll send that request along with your cookies. The idea behind the anti-forgery token is that even when the web browser sends all that information, if the token doesn't match with the one that you create on a legit request submitted from your application, it'll fail.
If you don't want your cookies being sent via cross-site requests, you can use the samesite flag for your cookies. Here you can decide between Strict and Lax mode. In Strict mode, you'll never send your site cookies via cross-site requests, so you don't need to care about session cookies being sent. The problem here is that if you're redirected from a different site, from example, if you're here, and try to go to facebook (if facebook used strict mode), your cookies will not be sent, and you'll need to authenticate again (it can be an annoying or a good feature, depending of your application and your user-base).
The Lax mode is pretty similar, but in this mode, you'll only send your cookies via safe HTTP verbs (GET, HEAD, OPTIONS and TRACE), so you still get your protection against POST/PUT XSRF attacks, and you don't have an annoying behaviour for the GET requests. It's up to you to decide which one will be the better option for your app.
More info about XSRF and samesite cookies: http://arnoldcer.com/2017/03/14/cross-site-request-forgery-what-it-is-how-to-exploit-it-and-how-to-defend-against-it/
I'm fairly new to website development. I'm working on a site where the user logs in with username/password, and gets a sessionID from the server in response. This sessionID is sent back to the server (and a new one returned) with each request.
I'd like the site to work properly if the user opens it in multiple tabs or windows. i.e. once logged in at one tab, opening a members-only URL in another tab works without loggin in. (And, logging out in one tab logs out from all.) I see no way of doing this without storing the latest sessionID in a cookie. That way the latest sessionID can be "shared" among all tabs.
However I am starting to read up on cookies, and some of the security threats. I was unaware that cookies were sent with every request. I don't need to send my cookie to the server, ever. The sessionID is added to the xhr request's headers -- not read as a cookie. So I'm wondering if there is a way to disable sending of this cookie. My only purpose for it is to allow multiple tabs/windows in the same browser to share the same session.
I was reading up on the path parameter for cookies. Apparently this can be used to restrict when the cookie is sent to a server? What if I set the path to something that would never be used? Would this prevent the cookie from ever being sent out automatically? I only want to access it from JavaScript.
A coworker has put a lot of safeguards into the server-side of this application, which I won't go into here. So this question is just about what client-side precautions I can and should take, particularly with cookies, for optimal security. If there is a better way to allow a members-only site to work properly with multiple tabs open at once, I'm all ears.
I discovered just now that in HTML 5 there is local storage, which stores key/value pairs much like a cookie, but is not sent with every server request. Since it's supported in every browser except IE 7 and earlier, I'll be switching to this to enable sharing data between tabs when available, and use cookies instead on IE 7 and earlier.
The sessionID is stored in a cookie already there's no need to manage it. Because the HTTP protocol is stateless the only way to maintain state is through a cookie. What happens when you set a session value the server will look up the dictionary of items associated with that cookie id (session Id).
What is meant by stateless is that between requests HTTP does not know if your still alive or have closed your browser. Therefore with each request the browser will attach all cookie values to the request on the domain. SessionId is stored in the cookie automatically when they go to your site. The Server then uses that value to look up anything you've set in the users session.
Depending on which programming language and/or server you're using the session could be handled differently but that's usually abstracted away from the programmer.
Now with respect to sessions, there are a number of different things that make them insecure. For example if an attacker were able to get their hands on your session cookie value they could replay that cookie and take over your session. So sessions aren't a terribly secure way of storing user information. Instead what most people do is create an encrypted cookie value with the users details, the cookie could be a "session cookie" meaning as soon as the user closes their browser window the cookie is thrown away from the browser. The encrypted cookie contains user information and role information as well as some identifier (usually the clients ip address) to verify that the user who is submitting the request is the same user the cookie was issued to. In most programming languages there are tools that help in abstracting that away as well (such as the ASP.NET membership provider model).
Check out some details on the HTTP protocol and HTTP cookies on Wikipedia first
http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
http://en.wikipedia.org/wiki/HTTP_cookie
and check out the membership provider model on ASP.NET, it's a really good tool for helping to secure your site.
http://msdn.microsoft.com/en-us/library/sx3h274z(v=vs.100).aspx
Preventing the browser sending cookies seems to defeat the object of using cookies in the first place.
If you don't want the sessionID to be sent with each request, why set the cookie? A better solution would be to use a custom response header that you send from the server to the browser - this will then be under your control and will not be sent automatically with all browser requests. You are using request headers to send your sessionID anyway so you could receive them from the server using a custom header and read this into your JavaScript from each XHR.
Instead of using a cookie I'm using a JWT token which gets send with every request. Every request is a POST request so that the token does not get saved in the browser's history.
It's a single-page app.
The token looks like:
{
userId: 12345678,
expires: <UNIX timestamp>,
otherInfo: <something>
}
Everything is SSL secured.
The token is created on the server when the user logs on.
Would this be a good way to replace a cookie or do you see any flaws?
No, this is not a good solution. Using cookies (with a httpOnly flag) for cross-request persistence is not optional - it's the only way to safely store session credentials, in such a way that on-page JavaScript code cannot access it directly.
This is essential to prevent eg. session stealing in an XSS attack, by ensuring that scripts cannot access the credentials, but they can still be used in requests to the server.
Your use of JWT doesn't seem to really solve a problem, either - why can't you just use session cookies using an existing session implementation? This kind of thing is precisely is what they're made for.