Using Timestamps to Prevent Session Hijacking? - encryption

I have been looking at ways to guard against session-hijacking, where someone steals a session cookie and uses it to gain access to the system.
Programs such as http://codebutler.com/firesheep make it easy to sniff sessions on open Wireless networks, and other ways of getting sessions include cross-site scripting attacks, or just physically lifting them from a victim's computer.
Using SSL to secure all session-cookie/server communications is critical for preventing the Firesheep sniff, and setting HTTPOnly on the cookie helps prevent JavaScript from being able to read the session cookie in XSS attacks, but it's still vulnerable to AJAX-based attacks.
Another layer is to include a security token or a nonce in the session cookie that gets updated on each request. You store the token in a server-side datastore and in the cookie, and on each request you compare that the token in the cookie matches the token in the datastore.
If the tokens don't match that could be an indicator that someone stole the session and is trying to use it so you can either ignore the request or invalidate the session and require the user to re-authenticate. However, mismatched tokens could also result from a slow/flaky connection.
For example, you could have a case where the server receives a request from a real user, updates the session token in the server datastore and responds to the user with a session cookie that contains the updated token. But the user doesn't receive the response due to a slow/flaky connection so the user still has the old session token while the new one is stored on the server. When the user retries the request, the tokens won't match.
One way to mitigate this problem is for the sever to keep a history of the last few tokens and check that to see if they match, but then it becomes a situation of how many tokens to keep, and depending on how flaky the connection is or how click-happy the user is, the server may cycle through the history before the connection comes back and the user's session gets updated by the browser.
An alternative to keeping a token history is to timestamp each session and check if the timestamps are within some short, specified range, say 30 seconds. If the user's session cookie timestamp is within 30 seconds of the server's stored session timestamp, then the session is deemed authentic.
Example pseudocode
def authenticate_request():
if (stored_session.timestamp - session.timestamp > 30 seconds):
return False
return True
This avoids having to keep a token history -- the timestamp becomes the token -- but attackers have a 30 second window of opportunity to hijack the session after it's stolen. While this is true, the token-history alternative isn't any better because it gives attackers a potentially longer window of opportunity.
Other approaches of checking for IP address and User-Agent changes have issues too. User Agents are easily spoofed, and if an attacker is able to get a user's session, they can easily determine the User Agent through the same XSS code or some other means.
If the user is on a mobile device, their IP address may change frequently so that would result in many false positives. Furthermore, the attacker could be behind the same company firewall so the user and attacker's IP are the same to the external Web server.
Is using a timestamp token the right approach or is there a better way? Is the 30-second buffer about right? What edge cases am I missing?

I don't see how a timestamp would work. It would require the user to never spend more than 30 seconds on a page before sending another request to the server. I'm sure I spent a lot more than 30 seconds reading this page and typing up this response before pressing "Post".
It seems to me that there's an inherent problem that any data you send over the line could be intercepted and duplicated. Encryting a password doesn't solve the problem, because a hacker could intercept the encrypted value and then send that encrypted value. He doesn't necessarily care what the unencrypted value is.
Same story for any token you send. The hacker could intercept the token and duplicate it.
The only idea I've heard that seems to solve the problem is a challenge-and-response system using public and private keys: A creates a random character string, encrypts it using B's public key, and sends it to B. B decrypts that string using his private key and sends the decrypted value back along with his application data. A then validates that the decrypted value matches the original value. If it doesn't validate, he rejects the associated data.
A hacker can't intercept the message from A and spoof the response if he doesn't know B's private key. A hacker can't use a previosly-intercepted reply from B because the random string is different every time.

Related

How can I correlate session.sessionid and IIS Log session cookie?

We are logging some tracking information to a database table within a classic asp site. One of the pieces of information captured is the users session ID (session.sessionid). Examples of what is captured are:
808592330
14267388
78330403
Then, separately in our IIS logs, session cookies are logged as such (these do not relate to the above examples...I just grabbed from a log i happened to have open):
ASPSESSIONIDACCDBSTT=FKOFEKICECOLNGLOIFLFINEI
ASPSESSIONIDACCDBSTT=GLOFEKICEECEFHFFFCFFEPCA
Most important question is, how can I correlate the long sessionID to the "likely encoded and possibly hashed or encrypted" textual representation.
And, secondarily, what are the values appended to ASPSESSIONID representing? (ex. the "ACCDBSTT" in ASPSESSIONIDACCDBSTT)
According to this MSDN article (which is ancient, but certainly makes sense in my experience):
Session ID values are 32-bit long integers.
Each time the Web server is restarted, a random Session ID starting value is selected.
For each ASP session that is created, this Session ID value is
incremented.
The 32-bit Session ID is mixed with random data and
encrypted to generate a 16-character cookie string. Later, when a
cookie is received, the Session ID can be restored from the
16-character cookie string (ASPSESSIONID).
The encryption key used is randomly selected each time the Web server is restarted.
This makes it sound like it would be impossible/impractical to decrypt the cookie after the fact.
If what you want to do is match IIS log records with database changes, the way we accomplished this in the past was by adding an ASPSESSIONID column to our database AuditLog table. Every time we logged a change, we also grabbed just the ASPSESSIONID* cookie from Request.ServerVariables("HTTP_COOKIE") (session cookies aren't exposed through the Request.Cookies collection) and saved it in the DB as well. Then when we had issues we needed to track down, we'd just do a text search in the IIS log for the value of the cookie in the AuditLog table (or vice versa).

When are cookies are preferable than sessions?

public class ServletDemo extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException{
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
Cookie cookie = new Cookie("url","mkyong dot com");
cookie.setMaxAge(60*60); //1 hour
response.addCookie(cookie);
pw.println("Cookies created");
}
}
I am seeing Java Cookies concept .
There is a lot of stuff on cookies , use it when small data needs to be stored on client side.
But could you please tell me , when should we use Cookies exactly ??
And when cookies are preferable than sessions ??
This one part of a whole set of design decisions relating to where we need to keep state information when several computers are involved in a system.
When you say "session" I suspect that you mean the HttpSession that servlet containers will manage for you. It's actually quite likely that the HttpSession is actually maintained by using a cookie: the cookie just holds some kind of a key to a table of sessions.
This pattern of passing some kind of reduced amount of data back to the browser and having the server keep track of the main stuff is also pretty common. Sometimes folks use all three: cookie for, say, the small stuff, HttpSession as a convenient cache, and the database for stuff they really care about.
There's lots of factors to consider, here's a few:
How much data is it reasonable to send in a cookie, too much things are going to go slow.
How secure is this? Servers often assemble lots more data then the user entered in this session, how confident are we that something sensitive can't be hijacked or read if we send it back to the browser in a cookie?
How reliable is our choice of session mechanism? Lose the browser, lose that 5k holiday booking we were just about to buy? Lose the HttpSession on the server? Perhaps the same outcome? (Some app servers have session replication, but it's an overhead).
Personally, I find that usually the HttpSession API is so convenient that I never choose to use cookies. My rule of thumb is "if it's readily re-creatable keep it in the HttpSession, otherwise make sure it's persisted in a database, if necessary creating a database specifically for state management (and not forgetting the housekeeping of that database).
Examples of re-creatable things: Items retrieved from a database (we can always get them again), things that the user would not mind re-entering (say a few search criteria). Example of non-re-creatable: the 17 page completed insurance application form.
Cookies are less secure than sessions.
A session is fully-controlled by the server. In both cases the client needs to securely present authentic session data, but with cookies there are more opportunities to sneak a look at what's going on internally. The consequences of cookie theft are in general worse then the theft of an opaque session ID.
Cookies can be faster to develop with because the server doesn't have set up session databases and the like, but they're a lower-quality solution if you care about design.
To answer your specific question, cookies are preferable to sessions when cookies can do what you can't do with sessions. I see two reasons to use them:
when you need some information about the client, and this information must keep existing across multiple client sessions, even if the user closes his browser. For example, an automatic login uses cookies: at the first request of a client session, the cookie is sent, and the web site is thus able to identify the user.
when you need to share some information between information between several web applications, provided their are all served from the same domain. For example, single sign-on can use cookies. The first application authenticates the user and sets a token cookie, which is sent to the second application. the second application may then use this cookie to automatically authenticate the user.

Is it possible to send HTTP Request without cookies?

I have to send some private data once from server to browser. I want to store it in a cookie. This data will be using later in Javascript code. But I want to send never(!) this private data to server when the browser does HTTP Request (because of security).
I know that I can set "path" value in cookie (to i.e. some abstract path) but then I won't be able to read this cookie (I'll be able to read from this abstract path, but if so, the browser send this cookie to server once - but as I said this data can't be sent to server).
So, my question is: is it somehow possible not to send a cookie with HTTP Request?
If you're sending this private data from server to browser then it is being exposed anyway. I don't think it matters much that it will be included in subsequent requests.
In general you should never place private data in cookies, at least not unless encrypted. So either a) do all of this over https or b) encrypt the data. But I'm guessing that b) will be a problem as you'll have to decrypt on the client side.
To be honest it sounds like you need to rethink your strategy here.
I don't think you'll be able to force the browser not to resend the cookie up if it's valid for that request.
Perhaps a better way would be to delete the cookie within the JS once you've read your data from it:
http://techpatterns.com/downloads/javascript_cookies.php
If you need to have it back in the JS again on the next response, just have the server re-send it, and delete it again on the client side.
I should say that sending data which you would deem to be 'private' in this way does not seem entirely appropriate on the face of it - as this information could easily be viewed using a proxy of some type sat between the browser and the server.
As Richard H mentioned, data in cookies is visible to the user if they know where to look. So this is not a good place to store secrets.
That said, I had a different application which needed to store lots of data client-side and ran into this same problem. (In my application, I needed to make the application able to run offline and keep the user actions if the PC crashes or website is down.) The solution is pretty simple:
1) Store the cookie data in a JavaScript variable. (Or maintain it in a variable already.)
2) Remove the cookies. Here's a function that can erase a cookie:
function cookieErase (name) {
document.cookie = name+'=; Max-Age=-99999999;path=/';
}
If you have more than one cookie (as was my case), you have to run the above function for every cookie you have stored. There is code to iterate each cookie, but in practice you probably know the names of the large cookies already and you might not want to delete other cookies your website is relying on.
3) Send the request as you would normally.
4) Restore the cookie data from the saved variables.
Here are some optimizations you can use:
1) Only trigger this code on a status 400 bad request (which is what you get back if the cookie data is too large). Sometimes, your data isn't too big, so deleting is unnecessary.
2) Restore the cookie data after a timeout if it isn't needed immediately. In this way, you can make multiple requests and only restore the data if there is idle time. This means your users can have a fast experience when actively using your website.
3) The moment you can, try to get any data moved to the server-side so the burden on the client/communication is less. In my case, the moment that the connection is back up, all actions are synchronized as soon as possible.

Using Cookies for Web Session State - What are the pitfalls?

Using in-process session state is evil when it comes to scaling web applications (does not play well with clusters, bombs out when server recycles).
Assuming you just need to keep a small amount of information in the session state, what is the downside of using encrypted cookie items for this purpose rather than specific state servers/db’s?
Obviously using cookies will create a small amount of network overhead, and clearly you operate under the assumption that cookies are enabled on the client browser/mobile device.
What other pitfalls can you see with approach?
Is this a good option for simple, scalable and robust sessions?
This is an excellent approach for simple, scalable, and robust sessions.
Of course the quality of your crypto is important, and that is often something that often proves tricky to get right, but it's possible to do.
I disagree with some of the other posters:
Any replay attack that can be launched against an encrypted cookie value can be launched against a session key stored as a cookie. Use https if this matters.
Session data stored in a state server or database is also lost if the cookie is cleared; when the session key is lost the session can no longer be retrieved.
Another pitfall is that they can be stolen and replayed on your site.
BTW: Instead of storing some stuff in the cookie, you should also look at storing a key in the cookie and using something like memcached (memcached works across server farms).
Well usually a cookie is used for the session ID, so as long as the amount of information is small it would be a good option to store the information in the cookie, though you shouldn't store anything of value (like CC numbers, SSN, etc) should really be stored in a cookie, even if encrypted.
I'm no expert, but in my experience I've found the following to be true (at least using PHP, and ASP.Net).
Cookie
[pro] Scales well, since it's transmitted on every request
[pro] Cookie can be required to submit only through an SSL connection
[pro] Can be used cross-server technologies, and cross-server machines
[con] Data is transmitted on every request and response
[con] Needs to be enabled on browser
State Server / DB
[pro] Data stored only on server
[pro] Data persists even if user clears cookies
[pro] Can be used cross-server technologies
[con] requires an ID to be passed on request/response (thus requires cookies or appending to every URL)
[con] doesn't scale well in default modes, but if an entire machine(s) can be devoted specifically and exclusively to state then this isn't much of an issue. Plenty of other scaling techniques out there that can be followed for scalability.
[con] Requires a session ID variable passed through URL or Cookie or other means, to keep the user tied to the data.

How do I prevent replay attacks?

This is related to another question I asked. In summary, I have a special case of a URL where, when a form is POSTed to it, I can't rely on cookies for authentication or to maintain the user's session, but I somehow need to know who they are, and I need to know they're logged in!
I think I came up with a solution to my problem, but it needs fleshing out. Here's what I'm thinking. I create a hidden form field called "username", and place within it the user's username, encrypted. Then, when the form POSTs, even though I don't receive any cookies from the browser, I know they're logged in because I can decrypt the hidden form field and get the username.
The major security flaw I can see is replay attacks. How do I prevent someone from getting ahold of that encrypted string, and POSTing as that user? I know I can use SSL to make it harder to steal that string, and maybe I can rotate the encryption key on a regular basis to limit the amount of time that the string is good for, but I'd really like to find a bulletproof solution. Anybody have any ideas? Does the ASP.Net ViewState prevent replay? If so, how do they do it?
Edit: I'm hoping for a solution that doesn't require anything stored in a database. Application state would be okay, except that it won't survive an IIS restart or work at all in a web farm or garden scenario. I'm accepting Chris's answer, for now, because I'm not convinced it's even possible to secure this without a database. But if someone comes up with an answer that does not involve the database, I'll accept it!
If you hash in a time-stamp along with the user name and password, you can close the window for replay attacks to within a couple of seconds. I don't know if this meets your needs, but it is at least a partial solution.
There are several good answers here and putting them all together is where the answer ultimately lies:
Block-cipher encrypt (with AES-256+) and hash (with SHA-2+) all state/nonce related information that is sent to a client. Hackers with otherwise just manipulate the data, view it to learn the patterns and circumvent everything else. Remember ... it only takes one open window.
Generate a one-time random and unique nonce per request that is sent back with the POST request. This does two things: It ensures that the POST response goes with THAT request. It also allows tracking of one-time use of a given set of get/POST pairs (preventing replay).
Use timestamps to make the nonce pool manageable. Store the time-stamp in an encrypted cookie per #1 above. Throw out any requests older than the maximum response time or session for the application (e.g., an hour).
Store a "reasonably unique" digital fingerprint of the machine making the request with the encrypted time-stamp data. This will prevent another trick wherein the attacker steals the clients cookies to perform session-hijacking. This will ensure that the request is coming back not only once but from the machine (or close enough proximity to make it virtually impossible for the attacker to copy) the form was sent to.
There are ASPNET and Java/J2EE security filter based applications that do all of the above with zero coding. Managing the nonce pool for large systems (like a stock trading company, bank or high volume secure site) is not a trivial undertaking if performance is critical. Would recommend looking at those products versus trying to program this for each web-application.
If you really don't want to store any state, I think the best you can do is limit replay attacks by using timestamps and a short expiration time. For example, server sends:
{Ts, U, HMAC({Ts, U}, Ks)}
Where Ts is the timestamp, U is the username, and Ks is the server's secret key. The user sends this back to the server, and the server validates it by recomputing the HMAC on the supplied values. If it's valid, you know when it was issued, and can choose to ignore it if it's older than, say, 5 minutes.
A good resource for this type of development is The Do's and Don'ts of Client Authentication on the Web
You could use some kind of random challenge string that's used along with the username to create the hash. If you store the challenge string on the server in a database you can then ensure that it's only used once, and only for one particular user.
In one of my apps to stop 'replay' attacks I have inserted IP information into my session object. Everytime I access the session object in code I make sure to pass the Request.UserHostAddress with it and then I compare to make sure the IPs match up. If they don't, then obviously someone other than the person made this request, so I return null. It's not the best solution but it is at least one more barrier to stop replay attacks.
Can you use memory or a database to maintain any information about the user or request at all?
If so, then on request for the form, I would include a hidden form field whose contents are a randomly generated number. Save this token to in application context or some sort of store (a database, flat file, etc.) when the request is rendered. When the form is submitted, check the application context or database to see if that randomly generated number is still valid (however you define valid - maybe it can expire after X minutes). If so, remove this token from the list of "allowed tokens".
Thus any replayed requests would include this same token which is no longer considered valid on the server.
I am new to some aspects of web programming but I was reading up on this the other day. I believe you need to use a Nonce.
(Replay attacks can easily be all about an IP/MAC spoofing, plus you're challenged on dynamic IPs )
It is not just replay you are after here, in isolation it is meaningless. Just use SSL and avoid handcrafting anything..
ASP.Net ViewState is a mess, avoid it. While PKI is heavyweight and bloated, at least it works without inventing your own security 'schemes'. So if I could, I'd use it and always go for mutual authent. Server-only authentification is quite useless.
The ViewState includes security functionality. See this article about some of the build-in security features in ASP.NET . It does validation against the server machineKey in the machine.config on the server, which ensures that each postback is valid.
Further down in the article, you also see that if you want to store values in your own hidden fields, you can use the LosFormatter class to encode the value in the same way that the ViewState uses for encryption.
private string EncodeText(string text) {
StringWriter writer = new StringWriter();
LosFormatter formatter = new LosFormatter();
formatter.Serialize(writer, text);
return writer.ToString();
}
Use https... it has replay protection built in.
If you only accept each key once (say, make the key a GUID, and then check when it comes back), that would prevent replays. Of course, if the attacker responds first, then you have a new problem...
Is this WebForms or MVC? If it's MVC you could utilize the AntiForgery token. This seems like it's similar to the approach you mention except it uses basically a GUID and sets a cookie with the guid value for that post. For more on that see Steve Sanderson's blog: http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/
Another thing, have you considered checking the referrer on the postback? This is not bulletproof but it may help.

Resources