I am building a Web Application using Angular 2 and the backend service built in ASP.NET Core Web API.
For authentication, I am thinking of using JWT and storing the token in a Secure HttpOnly Cookie.
For extra security, I am also thinking of capturing the IP Address for the user on the initial login and on each request after the initial login, revoking the token if the IP Address changes.
So the questions I have are:
Is this extra level of security worth it?
Will there be any problems with the IP check I am thinking of using? Based what I know about networking, I don't think an IP Address will legitimately change between request. Even if it does, I think it would be very rare. However I am not going to pretend I know enough about networking to confirm that.
Edit 1
(In response to an answer).
Thank you for answering my question. I have responded to a few of your responses.
My initial thought was that using JWT in a cookie to connect to an API is not the typical use case, why don't you use a standard MVC app then, but that's not your question and actually it's equally secure as long as the token is in a secure, httponly cookie (and of course the implementation is correct). It's just a bit unusual I think.
I am not sure why you consider using cookies this way unusual?
Is it because most of the time cookies are used for session state? I personally think storing a token in a secure cookie instead of keeping the token in a http header or local storage should be a very typical use case because of how much more secure it is. Unless I am missing something?
So I guess I will ask what is the disadvantage of doing it this way?
It depends. If you are worried about session theft, probably yes. If you keep the token in an httponly cookie (protected against xss), that's more secure than a token anywhere else, but still, your threat model may show different threats and validate your concern. The usual problem is you can't do this, see below.
This application will be dealing with a lot of PPI information so I do have a concern on token theft.
Most probably, there will be problems. It depends on your users, how and from where they use your application. If they use mobile devices, IP addresses will change a lot and such a solution is out of the question. If they are corporate users in a company internal network, it can be feasible. Anything inbetween is a gray area. A typical home user will have their IP changed once in a while, most people get dynamic IP allocation from their internet providers. An IP lease typically lasts a few weeks (at least where I live), but ISPs can configure it any way they want, it can be a day or even shorter.
My impression with IP address lease renew is majority of the time the client gets the same IP address. However I should not make that assumption I suppose?
However I can see this can be more of a problem with mobile devices. Some of the clients will be on the road often so this is a good point you have made that can become a problem.
One typical solution you can choose to do is offer this option on the login screen. If a user chooses to use IP address validation, he opts for greater security but accepts the fact that sometimes he may have to log in again. Or he can choose lower security with his session being more stable. Whether it's worth to explain this to your users is I think a business decision.
Never thought about giving the client an option which does sound like a good idea.
Edit 2
(In response to an answer).
Also I'm not sure whether your JWT only has a session id or if your server is stateless and all session data is in the JWT. In the first case, you don't even need the JWT, you could just pass the session id as normal, and standard .Net MVC does that for you. If it's session data too, JWTs are unencrypted by default, so session contents will be visible to endusers, which may or may not be a problem. (And a JWT is protected from tampering by its signature, so it's only about confidentiality, not integrity). Storing session data in the JWT and the JWT in the cookie may also face cookie size issues, depending on your target browsers.
My backend ASP.NET Core Web API will be stateless. The decision has already been made to use Angular so discussing is a moot point.
As for why I think using a JWT this way is a little unusual: I think JWTs are mostly used when tokens need to be passed to different URLs (to different services). For this purpose, httpOnly cookies are obviously inadequate because of the same origin rule. If you can afford using httpOnly cookies, you could just store your session info on the server side.
A much as I would like to discuss the above topic because my solution could be flawed, I think the powers that be may close this post for getting off topic?
Might be more appropriate to ask a new question targeted toward the above subject?
As for lease renews resulting in the same IP: Well, they don't always. It depends on your business case, but some ISPs give you IPs only for a short time. If it's ok for your users to get logged out once in a while, then it may be ok for wired (home) users. And it is definitely a big problem with mobile devices.
My initial thought was that using JWT in a cookie to connect to an API is not the typical use case, why don't you use a standard MVC app then, but that's not your question and actually it's equally secure as long as the token is in a secure, httponly cookie (and of course the implementation is correct). It's just a bit unusual I think.
On to the point, your question is very valid as is your concern about problems.
Is this extra level of security worth it?
It depends. If you are worried about session theft, probably yes. If you keep the token in an httponly cookie (protected against xss), that's more secure than a token anywhere else, but still, your threat model may show different threats and validate your concern. The usual problem is you can't do this, see below.
Will there be any problems with the IP check I am thinking of using?
Most probably, there will be problems. It depends on your users, how and from where they use your application. If they use mobile devices, IP addresses will change a lot and such a solution is out of the question. If they are corporate users in a company internal network, it can be feasible. Anything inbetween is a gray area. A typical home user will have their IP changed once in a while, most people get dynamic IP allocation from their internet providers. An IP lease typically lasts a few weeks (at least where I live), but ISPs can configure it any way they want, it can be a day or even shorter.
So reality is if you have a normal, usual userbase, you will most probably run into problems.
One typical solution you can choose to do is offer this option on the login screen. If a user chooses to use IP address validation, he opts for greater security but accepts the fact that sometimes he may have to log in again. Or he can choose lower security with his session being more stable. Whether it's worth to explain this to your users is I think a business decision.
Update in response to Edit 1 :)
As for why I think using a JWT this way is a little unusual: I think JWTs are mostly used when tokens need to be passed to different URLs (to different services). For this purpose, httpOnly cookies are obviously inadequate because of the same origin rule. If you can afford using httpOnly cookies, you could just store your session info on the server side. Also I'm not sure whether your JWT only has a session id or if your server is stateless and all session data is in the JWT. In the first case, you don't even need the JWT, you could just pass the session id as normal, and standard .Net MVC does that for you. If it's session data too, JWTs are unencrypted by default, so session contents will be visible to endusers, which may or may not be a problem. (And a JWT is protected from tampering by its signature, so it's only about confidentiality, not integrity). Storing session data in the JWT and the JWT in the cookie may also face cookie size issues, depending on your target browsers.
As for lease renews resulting in the same IP: Well, they don't always. It depends on your business case, but some ISPs give you IPs only for a short time. If it's ok for your users to get logged out once in a while, then it may be ok for wired (home) users. And it is definitely a big problem with mobile devices.
I think you can do it with JWT and IP. When the user logs in. Capture the IP for the length of the session. At every login Capture IP then use that to validate the Token is from the owner who started the session. If another IP hits the system. force a revalidate and new token. IP+JWT+Password = login. If you had mobile apps that required 1 login and always remember the login. User never has to enter login again. Then cache the userid\password in the application {securely} and then resend it automatically when the IP changes. JWT is secure when using SSL Difference between SSL and JWT
Sorry for reviving this, but lately I have been thinking a lot about encryption and security and thought of something (that I guess is pretty similar to what HTTPS does)
When user logs in, the server responds with a normal greeting (user info, JWT and whatever other data you need to pass) + you will pass a public key
Have a backend that supports any asymmetric encryption method (I like RSA) and have your front (also needs to run the same encryption method) end receive the public key, encrypt the data, and send it to the server with every subsequent request.
If any of the data that the user needs to provide changes, revoke.
You can even keep track of a clock, if its off by too much, revoke.
For extra layer, have the client transmit a public key on login/signup and boom, hermetic comms like a hazmat suit.
Related
UPDATE: I have concluded my research on this problem and posted a lengthy blog entry explaining my findings: The Unspoken Vulnerability of JWTs. I explain how the big push to use JWTs for local authentication is leaving out one crucial detail: that the signing key must be protected. I also explain that unless you're willing to go to great lengths to protect the keys, you're better off either delegating authentication via Oauth or using traditional session IDs.
I have seen much discussion of the security of JSON Web Tokens -- replay, revocation, data transparency, token-specified alg, token encryption, XSS, CSRF -- but I've not seen any assessment of the risk imposed by relying on a signing key.
If someone breaches a server and acquires a JWT signing key, it seems to me that this person could thereafter use the key to forge unexpired JWTs and secretly gain access. Of course, a server could look up each JWT on each request to confirm its validity, but servers use JWTs exactly so they don't have to do this. The server could confirm the IP address, but that also involves a lookup if the JWT is not to be trusted, and apparently doing this precludes reliable mobile access anyway.
Contrast this with a breach of a server based on session IDs. If this server is hashing passwords, the attacker would have to snag and use a session ID separately for each user before it expires. If the server were only storing hashes of the session IDs, the attacker would have to write to the server to ensure access. Regardless, it seems that the attacker is less advantaged.
I have found one architecture that uses JWTs without this disadvantage. A reverse proxy sits between untrusted clients externally and a backend collection of microservices internally, described here by Nordic APIs. A client acquires an opaque token from an authorization server and uses that token to communicate with the server app for all requests. For each request, the proxy translates the opaque token into a JWT and caches their association. The external world never provides JWTs, limiting the damage wrought by stealing keys (because the proxy goes to the authentication server to confirm the opaque tokens). However, this approach requires dereferencing each client token just as session IDs require per-request dereferencing, eliminating the benefit of JWTs for client requests. In this case, JWTs just allow services to pass user data among themselves without having to fully trust one another -- but I'm still trying to understand the value of the approach.
My concern appears to apply only to the use of JWTs as authentication tokens by untrusted clients. Yet JWTs are used by a number of high-profile APIs, including Google APIs. What am I missing? Maybe server breaches are rarely read-only? Are there ways to mitigate the risk?
I believe you're thinking about this the wrong way. Don't get me wrong, it's great you're considering security, however the way you're approaching it in regards to double checking things server-side, adding additional checks that defeat the objective of stateless sessions, etc, appear to be along a one way street towards the end of your own sanity.
To sum up the two standard approaches:
JWTs are sessionless state objects, MAC'd by a secret key held server side.
Traditional Session Identifiers are stored either in memory or in a database server-side, and as you say are often hashed to prevent sessions from being hijacked should this data be leaked.
You are also right that write access is often harder for an attacker to achieve. The reason is that database data is often extracted from a target system via a SQL injection exploit. This almost always provides read access to data, but it is harder to insert data using this technique, although not impossible (some exploits actually result in full root access of the target machine being achieved).
If you have a vulnerability that allows access to the key when using JWTs or one that allows database tables to be written to when using session identifiers, then it's game over - you are compromised because your user sessions can be hijacked.
So not more damaging necessarily, it all depends on the depth of the vulnerability.
Double check that the security of your JWT keys align with your risk appetite:
Where are they stored?
Who has access?
Where are backups stored?
Are different keys used in pre-production and production deployments of your app?
The ways to mitigate is as good practise dictates with any web app:
Regular security assessments and penetration testing.
Security code reviews.
Intrusion detection and prevention (IDS/IPS).
WAF.
These will help you evaluate where your real risks lie. It is pointless concentrating on one particular aspect of your application so much, because this will lead to the neglect of others, which may well be higher risk to your business model. JWTs aren't dangerous and have no more risk than other components of your system necessarily, however if you've chosen to use them you should make sure you're using them appropriately. Whether you are or not comes down to the particular context of your application and that is difficult to assess in a general sense, so I hope my answer guides you in the right direction.
When an attacker is able to get hold of the signing key in a JWT based system that means that he is able to get access to the server backend itself. In that case all hope is lost. In comparison to that, when the same attack succeeds in session based systems the attacker would be able to intercept username/password authentication requests to the backend, and/or generate sessions ids himself, and/or change the validation routines required to validate the session ids and/or modify the data to which the session id points. Any security mechanism used to mitigate this works as well for session systems as for JWT systems.
So I just noticed that one of the internet banks websites is passing session id as url parameter. ( See image below )
I didn't previously see anywhere that ';' in url, in this case it is after 'private;'.
1) What is the use of this ';'?
2) And why internet bank, which needs to be securest place in the internet is passing session id as url parameter?
At first, I thought they are doing it because some of the users disallow use of cookies, but then again, if they allow it, use cookies, if not - url, but I do allow use of cookies, so obviously thats not the case.
3) I guess then they should have some other security measures? What they could be?
4) And what one can possibly do if he knows others valid session id?
As I know, you can quite easily log into others peoples session if you know that id, because its not hard to edit cookies and its much easier to pass that session id as url parameter, especially if you have something like:
session_id($_GET[sessionid]);
Thanks!
1) You should ask whoever designed the application your red box is covering. URL can be anything you want; the convention of key=value&key2=value2 is just that - a convention. In this case, it's Java, and it commonly uses the convention of ;jsessionid=.... for its SID.
2) It's not that big of a deal. Normal users can't copy-paste cookies like they can copy-paste a GET parameter, but power users can do whatever they want (using Mechanize, wget, curl and other non-browser means, or even browser extensions). And if you allow it for some users and disallow for some, it's not really much of a security precaution, is it? Basically, cookie SID will make the attack a bit harder, but it's like putting your front door key under the mat - definitely doesn't keep your door secure. Additionally, cookies are shared between tabs: if a site wants you to be logged in with two accounts at once, you can't do it with cookies.
3) Serverside security, yes. One effective countermeasure is one-time SIDs (each time you visit a page, the server reads the session from the current SID, then starts a new session with a new SID for the next request). A less effective but still good method is to validate other information for consistency (e.g. - still same IP? Still same browser?)
4) Yes, if you know someone's valid SID, and the server does not adequately protect against session fixation, you can "become" that person. This might enable the attacker to, say, pay his bills with your money, for instance.
So, #Amadan correctly covered #1 and #4. But there's a bit more that needs expansion.
Using Session identifiers in a URL can be a major problem. There are a few cases where it's critically bad:
Session Hijacking:
If a user copy-pastes a URL into an email.
In this case, the attacker can simply read the email, and steal the session identifier (thereby resuming the session).
You could partially defend against this by making session lifetimes short, and validating things like IP addresses or User Agents in the session. Note that none of these are foolproof, they just make it "slightly" harder to attack.
If the connection is ever downgraded to HTTP.
If they are not using Http-Strict-Transport-Security (HSTS), then an attacker may be able to successfully downgrade the session to HTTP only (via MITM style attack). If the server isn't setup perfectly, this can cause the URL to leak to the attacker, and hence the session identifier.
Session Fixation Attacks
An attacker can craft a session identifier, and send the user a forged link with that session identifier. The user then logs in to the site, and the session is now tied to their account.
You can mitigate this by strictly rotating session identifiers every time the session changes (log in, log out, privilege upgrade or downgrade, etc). But many servers don't do this, and hence are susceptible to fixation style attacks.
The reason that cookie sessions are seen as more secure is not because they are harder to edit. It's because they are more resistant to fixation attacks (you can't create a URL or link or form or js or anything that sends a fraudulent cookie on behalf of the user).
Why the bank uses a URL parameter? I have two guesses:
Because they want to support those who don't allow cookies.
Which is sigh worthy.
They don't know any better.
Seriously. If it's not in a compliance doc or NIST recommendation, then they likely don't do it. Hell, there are implemented NIST recommendations that are known to be insecure, yet are still followed because it's in writing.
What is the use of this ;?
This is just a query string separator. & isn't the only sub-delim specified in the URL specification (RFC 3986).
And why internet bank, which needs to be securest place in the internet is passing session id as url parameter?
It could be that this session ID is never used, and the actual session identifier user is passed in cookies or in POST data between each navigated page. The only way to verify this is to try copying the URL into another browser to see if your session is resumed, however then again they may be checking things like User Agent - not real security but would dissuade casual attacks. Do not try this on a live system you do not have permission to do so on as it would be illegal. If you want to learn about security download something like Hacme Bank and try on there.
I guess then they should have some other security measures? What they could be?
No doubt they will, otherwise this would be a huge security threat. The URL could be leaked in the referer header if there are any external links on the page. The types of security a bank uses for their website is too large to list here, however they should be meeting certain industry standards such as ISO/IEC 27001 that will cover the types of threat that their site would need to be secure against.
And what one can possibly do if he knows others valid session id? As I know, you can quite easily log into others peoples session if you know that id, because its not hard to edit cookies and its much easier to pass that session id as url parameter, especially if you have something like:
As the ID is displayed on the screen it might be possible to read it (although IDs are generally long). A more realistic attack is Session Fixation. This is where an attacker can set the Session ID of their victim. For example, sending them a link that includes the attacker's Session ID. When the victim follows it and then logs in, as the attacker has the same session, they are logged in too.
Storing the Session information in a cookie or in a URL are both viable methods. A combination may used as
Security session management and (Server) Session management are separate aspects:
The fundamental difference is that cookies are shared between browser windows/tabs, the url not.
If you want your user to be logged on when navigating to the same site in different tab, sharing the security session (=without a new logon procedure) then cookies are a good way.
To differentiate "sessions" per tab and associate distinct server sessions with distinct tabs (Think of the user running two "stateful" transactions in two different tabs in parallel), managing a sessionId on the client which can be different per tab is required. Cookies won't work here.
Putting it in the URL is one way to assure this information is routinely added to requests fired from the page (referrer header). Alternative methods would require specific code to add this information explicitly to each request which is more work.
See How to differ sessions in browser-tabs?
In an effort to increase performance, I was thinking of trying to eliminate a plain 'session cookie', but encrypt all the information in the cookie itself.
A very simple example:
userid= 12345
time=now()
signature = hmac('SHA1',userid + ":" + time, secret);
cookie = userid + ':' + time + ':' + signature;
The time would be used for a maximum expirytime, so cookies won't live on forever.
Now for the big question: is this a bad idea?
Am I better off using AES256 instead? In my case the data is not confidential, but it must not be changed under any circumstances.
EDIT
After some good critique and comments, I'd like to add this:
The 'secret' would be unique per-user and unpredictable (random string + user id ?)
The cookie will expire automatically (this is done based on the time value + a certain amount of seconds).
If a user changes their password, (or perhaps even logs out?) the secret should change.
A last note: I'm trying come up with solutions to decrease database load. This is only one of the solutions I'm investigating, but it's kind of my favourite. The main reason is that I don't have to look into other storage mechanism better suited for this kind of data (memcache, nosql) and it makes the web application a bit more 'stateless'.
10 years later edit
JWT is now a thing.
A signed token is a good method for anything where you want to issue a token and then, when it is returned, be able to verify that you issued the token, without having to store any data on the server side. This is good for features like:
time-limited-account-login;
password-resetting;
anti-XSRF forms;
time-limited-form-submission (anti-spam).
It's not in itself a replacement for a session cookie, but if it can eliminate the need for any session storage at all that's probably a good thing, even if the performance difference isn't going to be huge.
HMAC is one reasonable way of generating a signed token. It's not going to be the fastest; you may be able to get away with a simple hash if you know about and can avoid extension attacks. I'll leave you to decide whether that's worth the risk for you.
I'm assuming that hmac() in whatever language it is you're using has been set up to use a suitable server-side secret key, without which you can't have a secure signed token. This secret must be strong and well-protected if you are to base your whole authentication system around it. If you have to change it, everyone gets logged out.
For login and password-resetting purposes you may want to add an extra factor to the token, a password generation number. You can re-use the salt of the hashed password in the database for this if you like. The idea is that when the user changes passwords it should invalidate any issued tokens (except for the cookie on the browser doing the password change, which gets replaced with a re-issued one). Otherwise, a user discovering their account has been compromised cannot lock other parties out.
I know this question is very old now but I thought it might be a good idea to update the answers with a more current response. For anyone like myself who may stumble across it.
In an effort to increase performance, I was thinking of trying to
eliminate a plain 'session cookie', but encrypt all the information in
the cookie itself.
Now for the big question: is this a bad idea?
The short answer is: No it's not a bad idea, in fact this is a really good idea and has become an industry standard.
The long answer is: It depends on your implementation. Sessions are great, they are fast, they are simple and they are easily secured. Where as a stateless system works well however, is a bit more involved to deploy and may be outside the scope of smaller projects.
Implementing an authentication system based on Tokens (cookies) is very common now and works exceedingly well for stateless systems/apis. This makes it possible to authenticate for many different applications with a single account. ie. login to {unaffiliated site} with Facebook / Google.
Implementing an oAuth system like this is a BIG subject in and of itself. So I'll leave you with some documentation oAuth2 Docs. I also recommend looking into Json Web Tokens (JWT).
extra
A last note: I'm trying come up with solutions to decrease database
load. This is only one of the solutions I'm investigating
Redis would work well for offloading database queries. Redis is an in memory simple storage system. Very fast, ~temporary storage that can help reduce DB hits.
Update: This answer pertains to the question that was actually asked, not to an imagined history where this question was really about JWT.
The most important deviations from today's signed tokens are:
The question as originally posed didn't evince any understanding of the need for a secret in token generation. Key management is vital for JWT.
The questioner stated that they could not use HTTPS, and so they lacked confidentiality for the token and binding between the token and the request. In the same way, even full-fledged JWT can't secure a plain HTTP request.
When the question was revised to explain how a secret could be incorporated, the secret chosen required server-side state, and so fell short of the statelessness provided by something like JWT.
Even today, this homebrew approach would be a bad idea. Follow a standard like JWT, where both the scheme and its implementations have been carefully scrutinized and refined.
Yes, this is a bad idea.
For starters, it's not secure. With this scheme, an attacker can generate their own cookie and impersonate any user.
Session identifiers should be chosen from a large (128-bit) space by a cryptographic random number generator.
They should be kept private, so that attackers cannot steal them and impersonate an authenticated user. Any request that performs an action that requires authorization should be tamper-proof. That is, the entire request must have some kind of integrity protection such as an HMAC so that its contents can't be altered. For web applications, these requirements lead inexorably to HTTPS.
What performance concerns do you have? I've never seen a web application where proper security created any sort of hotspot.
If the channel doesn't have privacy and integrity, you open yourself up to man-in-the-middle attacks. For example, without privacy, Alice sends her password to Bob. Eve snoops it and can log in later as Alice. Or, with partial integrity, Alice attaches her signed cookie to a purchase request and sends them to Bob. Eve intercepts the request and modifies the shipping address. Bob validates the MAC on the cookie, but can't detect that the address has been altered.
I don't have any numbers, but it seems to me that the opportunities for man-in-the-middle attacks are constantly growing. I notice restaurants using the wi-fi network they make available to customers for their credit-card processing. People at libraries and in work-places are often susceptible to sniffing if their traffic isn't over HTTPS.
You should not reinvent the wheel. The session handler that comes with your development platform far is more secure and certainly easier to implement. Cookies should always be very large random numbers that links to server side data. A cookie that contains a user id and time stamp doesn't help harden the session from attack.
This proposed session handler is more vulnerable to attack than using a Cryptographic nonce for each session. An attack scenario is as follows.
It is likely that you are using the same secret for your HMAC calculation for all sessions. Thus this secret could be brute forced by an attacker logging in with his own account. By looking at his session id he can obtain everything except for the secret. Then the attacker could brute force the secret until the hmac value can be reproduced. Using this secret he can rebuild a administrative cookie and change his user_id=1, which will probably grant him administrative access.
What makes you think this will improve performance vs. secure session IDs and retrieving the userid and time information from the server-side component of the session?
If something must be tamper-proof, don't put it in the toddlers' hands. As in, don't give it to the client at all, even with the tamper-proof locking.
Ignoring the ideological issues, this looks pretty decent. You don't have a nonce. You should add that. Just some random garbage that you store along with the userid and time, to prevent replay or prediction.
If a user logs into the site, and says 'remember me', we get the unique identifier for the user, encrypt this with RijndaelManaged with a keysize of 256 and place this in a httponly cookie with a set expiration of say.. 120 days, the expiration is refreshed each successful request to the server.
Optionally we generate the initialization vector based upon the user agent and part of the ipv4 address (the last two octets).
Obviously theres no real expiration system built into this, the user could technically use this encrypted key forever (given we don't change the server side key)..
I considered the fact that to allow this feature I need to allow the user to be able to bypass the login and give me their unique id (which is a guid), I figured the guid alone was really hard to guess a real users guid, but would leave the site open to attack by botnots generating guids (I've no idea how realistic it is for them to find a legit guid).. so this is why theres encryption where the server knows the encryption key, and optionally the iv is specific to the browser and ip part.
Should I be considering a different approach where the server issues tickets associated to a user, and these tickets would have a known expiration date so the server stays in control of expiration? should I really care about expiration? remember me is remember me after all?
Looking forward to being humbled ;),
Cheers.
Very similar question.
The solution to your question is in this blog post
"Persistent Login Cookie Best
Practice," describes a relatively
secure approach to implementing the
familiar "Remember Me" option for web
sites. In this article, I propose an
improvement that retains all the
benefits of that approach but also
makes it possible to detect when a
persistent login cookie has been
stolen and used by an attacker.
As Jacco says in the comments: for in depth info about secure authentication read The Definitive Guide To Website Authentication.
Did you consider something like Open Id? As SO uses.
How important is the information that is being remembered? If it's not going to be anything very personal or important, just put a GUID in the cookie.
Including the IP address in the calculation is probably a bad idea, as it would make users using public networks be instantly forgotten.
Using brute force to find GUIDs is ridiculous, as there are 2128 possibilities.
I currently have a roll-your-own application security service that runs in my enterprise and is - for the most part - meeting business needs.
The issue that I currently face is that the service has traditionally (naively) relied on the user's source IP remaining constant as a hedge against session hijacking - the web applications in the enterprise are not directly available to the public and it was in the past perfectly acceptable for me to require that a users' address remain constant throughout a given session.
Unfortunately this is no longer the case and I am therefore forced to switch to a solution that does not rely on the source IP. I would much prefer to implement a solution that actually accomplishes the original designer's intent (i.e. preventing session hijacking).
My research so far has turned up this, which essentially says "salt your authentication token hash with the SSL session key."
On the face of it, this seems like a perfect solution, however I am left with a nagging suspicion that real-world implementation of this scheme is impractical due to the possibility that the client and server can at any time - effectively arbitrarily - opt to re-negotiate the SSL session and therefore change the key.
this is the scenario I am envisioning:
SSL session established and key agreed upon.
Client authenticates to server at the application level (i.e. via username and password).
Server writes a secure cookie that includes SSL session key.
Something occurs that causes a session re-negotiation. For example, I think IE does this on a timer with or without a reason.
Client submits a request to the server containing the old session key (since there was no application level knowledge of the re-negotiation there was no opportunity for a new, updated hash to be written to the client).
Server rejects client's credential due to hash match failure, etc.
Is this a real issue or is this a misapprehension on my part due to a (to say the least) less-than-perfect understanding of how SSL works?
See all topics related to SSL persistence. This is a well-researched issue in the load-balancer world.
The short answer is: you cannot rely on the SSLID -- most browsers renegotiate, and you still have to use the source IP. If the IP address is likely to change mid-session then you can force a soft-reauthentication, or use the SSLID as a bridge between the two IP changes (and vice-versa, i.e. only assume hijacking if both IP address and SSLID change at the same time, as seen by the server.)
2014 UPDATE
Just force the use of https and make sure that that you are not vulnerable to session fixation or to CRIME. Do not bother to salt your auth token with any client-side information because if an attacker was able to obtain the token (provided that said token was not just trivial to guess) then whatever means were used to obtain it (e.g. cross-site scripting, or the full compromising of the client system) will also allow the attacker to easily obtain any client-side information that might have gone into the token (and replicate those on a secondary system if needed).
If the client is likely to be connecting from only a few systems, then you could generate an RSA keypair in the browser for possibly every new client system the client connects from (where the public part is submitted to your server and the private part remains in what is hopefully secure client storage) and redirect to a virtual host that uses two-way (peer/client certificate) verification in lieu of password-based authentication.
I am wondering why it would not be just enough to simply
require ssl in your transport
encode inputs (html/url/attribute) to prevent cross-site scripting
require only POSTs for all requests that change information and
prevent CSRF as best you can (depending on what your platform supports).
Set your cookies to HTTPOnly
Yes, but there are several things you can do about it. The easiest it to simply cache the session key(s) you use as salt (per user), and accept any of them. Even if the session is renegotiated you'll still have it in your cache. There are details--expiration policy, etc.--but nothing insurmountable unless you are running something that needs to be milspec hardened, in which case you shouldn't be doing it this way in the first place.
-- MarkusQ