Implementing SCRAM - nonce validation and server/client keys - security

Technically two questions - but they are so heavily related I didn't want to split them up; but if the community feels I should, I will.
Following a recent question I am implementing SCRAM for a website login and web service API. Client environments will be .Net and Javascript (with Java likely in the future).
My first issue is basic: The protocol utilises a client and server key as key steps in the authentication process; and yet in order to be validated, both need to be known by both parties in advance since the protocol doesn't allow for exchange of these (to do so would result in a bit of a chicken and egg scenario). If you consider a Javascript client, for example, this means both keys are likely to be constants defined in the source - thus making them easy to fetch. So: why bother? Is it just to mitigate against 'Eve' where that 'Eve', for some reason, hasn't bothered to get the JS or client source code, which will necessarily be public!?
Secondly, like practically any other authentication mechanism it requires a client + server nonce.
Given that the authentication nonce, by definition, should never be used more than once (at least by the same user), this presumably means that a server must maintain a record of all nonce values used by all users forever. Unlike other data that we regularly archive off, such a table is only ever going to get bigger and queries against it likely to get slower and slower!
If that's correct, then it's technically unfeasible to implement this or almost any other authentication mechanism! Since I know that's plainly ridiculous; it must be common to define some additional scope that factors in a reasonable timescale as well.
As always with authentication and encryption; despite being a very experienced software developer I feel like I'm going back to school! What am I missing!?

both need to be known by both parties
in advance since the protocol doesn't
allow for exchange of these (to do so
would result in a bit of a chicken and
egg scenario).
Yes that's correct. Challenge response isn't a key-exchange protocol. It only norms, once client and server share a key, how to compute the same value from that key without transmitting in clear the key via network.
If you consider a Javascript client,
for example, this means both keys are
likely to be constants defined in the
source - thus making them easy to
fetch.
That's not a good idea. Alternatively client and server can agree on a key during a preliminary registration process.
Given that the authentication nonce,
by definition, should never be used
more than once (at least by the same
user), this presumably means that a
server must maintain a record of all
nonce values used by all users
forever.
NO. A new nonce should be generated for each new session using pseudo-random number generation. It's very improbable that you will get the same nonce twice, anyway It doesn't matter if a nonce it has already been used if the attacker don't know that .

Related

Are breaches of JWT-based servers more damaging?

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.

Penetration Testing HTML Posting Issue

We are planning to go for a security testing certificate. For that reason we are using Paros tool to test our system.
The system is written in GWT on front end and database connectivity is happening through Hibernate.
When we use this tool to test our application following behaviour is happening which needs to be restricted.
The tool is able to see the data which is passed to server. This is fine but when we make any changes in the data through tool it gets updated in the system on database end. This is a big security issue.
Can someone guide me in this?
If you're still looking for a solution to this problem, you could use request signing. The reason I didn't mention it earlier was because the only time I had seen request signing, there were certificates involved, and it was mostly using the Web Services Security Standard. The other time I recommended implementation of request signing was for a mobile application - its relatively easier to do there also, since you can use certificates that are on the device to perform the signing, and the server can verify this signature (essentially, a public key encryption mechanism).
As you mention in the comments, there are multiple aspects to it - one is to prevent XSRF, which is essentially including a nonce to ensure that an attacker cannot replay requests, or craft requests that might harm an authenticated user. This nonce will have to come from the server, since anything that you create using Javascript, the attacker can create also. This nonce will make sure that your request is time specific, and that it cannot be replayed at a later point of time.
However, a nonce isn't going to stop attacks where a user is in a hostile network, and an attacker is performing a MitM attack on all traffic. The attacker can still modify a request, and since the server has never seen that nonce before, it will accept the request as valid. To prevent this, you need to countermeasures in place - one, all traffic should go via SSL, and two, all requests must be signed so as to prevent tampering. The signature part is particularly hard, especially if you have to ensure that an attacker cannot perform the same signing. The examples I have seen of it involve certificate level authentication for the webapp, and using these certificates to then perform the signing - which might be too stringent a requirement for the application that you seem to be developing. Other methodologies involve using something that the user has/knows - maybe a token, password, secret answer, etc. - that cannot be replicated by an attacker, and using that information to sign requests.
Here's an example on how you can do this via PHP. I don't know if this mechanism can be adapted to do it for your purposes, though. OAuth might be another possible method, but since I've never seen an application do it that way, I am not very sure.
Sorry I don't have a specific methodology or examples of code for you to look at, but most implementations I've seen are only from a design standpoint, versus an actual code standpoint.

GWT/Javascript client side password encryption

I'm implementing authorization in my gwt app, and at the moment it's done in the following fashion:
The user signs up by putting his credentials in a form, and I send them in clear text to the server.
The server code hashes the received password using BCrypt and puts the hash in a database.
When the user logs in, his password is sent in the clear to the server, that checks it against the stored hash.
Now. The thing that's bothering me about this is the fact that I'm sending the password to the server in the clear, I keep thinking that I wouldn't be very pleased if an application I was using did that with my (use-for-everything-kind) password, but encrypting it on the client wouldn't really earn me anything, since the attackers could just use the hashed password as they would the clear one.
I have been googling all day for this, and it seems the Internet is quite unanimous when it comes to this - apparently there is nothing to be gained from client side password encryption. This, this and this are just a few examples of the discussions and pages I've come by, but there are many, many more, all saying the same thing.
This question, in light of all this, might seem a bit unnecessary, but I am hoping that somewhere, someone, will have another answer for me.
What can I do, if ssl isn't an option at this point, to ease my mind about this? Is there anything to be done, or will implementing some sort of client-encrypt-server-decrypt-scheme just be time-consuming feeble dead-horse-kicking?
For login, SSL should be your option, even at this point. If it's just for login, you don't need an expensive SSL farm, but at least you protect the (use-for-everything-kind) password, even though it's clear, that the remaining communication isn't secured [*]. This may mean, that you need to buy a certificate for just one login server, which can again save you a lot of money, depending on the certificate vendor.
For GWT, if you can't afford to encrypt all communication, you'll have to put the login on a separate page due to Same Origin Policy constraints.
If that still isn't an option, you can think about logging in via OpenID, just like stackoverflow does.
There can't be any secure communication over insecure media without some pre-shared secret - usually provided by the root certificates that are installed in a browser (BTW, it's funny/scary that browsers and even entire operating systems are usually downloaded via HTTP). Other systems, e.g. PGP, rely on previously established trust in a "Web Of Trust", but this is just another form of pre-shared secrets. There's no way around it.
[*] Using SSL for everything - unfortunately - comes with additional practical problems: 1) Page loads are a lot slower, especially if you have many elements on the page. This is due to SSL-induced round trips and the resulting latency, which you can't counter with even the fastest SSL farm. The problem is mitigated, but not fully eliminated by keep-alive connections. 2) If your page includes elements from foreign, non-HTTPS sites (e.g. images inserted by users), many browsers will display warnings - which are very vague about the real security problem, and are therefore usually unacceptable for a secure site.
A few additional thoughts (not a recommendation)
Let's assume the worst case for a moment, i.e. that you can't use SSL at all. In that case, maybe surprisingly, hashing the password (with a salt) before transmitting it, may actually be a bit better than doing nothing. Here's the reason: It can't defeat Mallory (in cryptography, a person who can manipulate the communication), but at least it won't let Eve (a person who can only listen) read the plaintext password. This may be worth something, if we assume that Eves are more common than Mallorys (?) But note, that in that case, you should hash the password again (with a different salt), before comparing it with the database value.
If SSL isn't an option then you obviously don't care enough about security ;)
But seriously - like you mentioned, client side encryption of the password is not a good idea. In fact, it's a very bad one. You can't trust the client side for jack - what if an attacker managed to alter the JS code (through XSS or while it was sent through the wire), so that your MD5/whatever hash function just passes the pass in cleartext? Not to mention that you should be using a good, strong, salted encryption method, like bCrypt - something which is just slow on the client and like mentioned before, doesn't quite add to the security of the app.
You could try bypassing some of those problems: by sending the hash library through some secure means (if that was possible in the first place, we wouldn't have to bother with all this now, would we?), by somehow sharing a common secret between the server and client and using that for encryption... but the bottom line is: use HTTPS when possible (in GWT it's hard to mix HTTPS and HTTP) and justified (if the user is stupid enough to use the same password for your not-security-related app and for his banking account, then it's highly likely that he/she used the same password on a number of other sites, any of which could lead to hijacking the password). Other means will just make you think that your application is more secure than it is and make you less vigilant.
Consider using SRP.
But that still won't help if a man in the middle sends you evil javascript than simpy sends a copy of your password to the attackers server.

Signed session cookies. A good idea?

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.

I need resources for API security basics. Any suggestions?

I've done a little googling but have been a bit overwhelmed by the amount of information. Until now, I've been considering asking for a valid md5 hash for every API call but I realized that it wouldn't be a difficult task to hijack such a system. Would you guys be kind enough to provide me with a few links that might help me in my search? Thanks.
First, consider OAuth. It's somewhat of a standard for web-based APIs nowadays.
Second, some other potential resources -
A couple of decent blog entries:
http://blog.sonoasystems.com/detail/dont_roll_your_own_api_security_recommendations1/
http://blog.sonoasystems.com/detail/more_api_security_choices_oauth_ssl_saml_and_rolling_your_own/
A previous question:
Good approach for a web API token scheme?
I'd like to add some clarifying information to this question. The "use OAuth" answer is correct, but also loaded (given the spec is quite long and people who aren't familiar with it typically want to kill themselves after seeing it).
I wrote up a story-style tutorial on how to go from no security to HMAC-based security when designing a secure REST API here:
http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
This ends up being basically what is known as "2-legged OAuth"; because OAuth was originally intended to verifying client applications, the flow is 3-parts involving the authenticating service, the user staring at the screen and the service that wants to use the client's credentials.
2-legged OAuth (and what I outline in depth in that article) is intended for service APIs to authenticate between each other. For example, this is the approach Amazon Web Services uses for all their API calls.
The gist is that with any request over HTTP you have to consider the attack vector where some malicious man-in-the-middle is recording and replaying or changing your requests.
For example, you issue a POST to /user/create with name 'bob', well the man-in-the-middle can issue a POST to /user/delete with name 'bob' just to be nasty.
The client and server need some way to trust each other and the only way that can happen is via public/private keys.
You can't just pass the public/private keys back and forth NOR can you simply provide a unique token signed with the private key (which is typically what most people do and think that makes them safe), while that will identify the original request coming from the real client, it still leaves the arguments to the comment open to change.
For example, if I send:
/chargeCC?user=bob&amt=100.00&key=kjDSLKjdasdmiUDSkjh
where the key is my public key signed by my private key only a man-in-the-middle can intercept this call, and re-submit it to the server with an "amt" value of "10000.00" instead.
The key is that you have to include ALL the parameters you send in the hash calculation, so when the server gets it, it re-vets all the values by recalculating the same hash on its side.
REMINDER: Only the client and server know the private key.
This style of verification is called an "HMAC"; it is a checksum verifying the contents of the request.
Because hash generation is SO touchy and must be done EXACTLY the same on both the client and server in order to get the same hash, there are super-strict rules on exactly how all the values should be combined.
For example, these two lines provides VERY different hashes when you try and sign them with SHA-1:
/chargeCC&user=bob&amt=100
/chargeCC&amt=100&user=bob
A lot of the OAuth spec is spent describing that exact method of combination in excruciating detail, using terminology like "natural byte ordering" and other non-human-readable garbage.
It is important though, because if you get that combination of values wrong, the client and server cannot correctly vet each other's requests.
You also can't take shortcuts and just concatonate everything into a huge String, Amazon tried this with AWS Signature Version 1 and it turned out wrong.
I hope all of that helps, feel free to ask questions if you are stuck.

Resources