I'm writing a webservice in Go.
Upon login, the user is returned a token, which behaves roughly like a cookie in the sense that the user must pass it in each subsequent request in order to be recognized.
Does my token generator has to be "cryptographically secure", ie. generated with high entropy?
How can I achieve this in Go, preferably using standard libraries or libraries written by crypto-competent people unlike me?
It would be beneficial for the token generator to be cryptographically secure, to reduce the ability of attackers to guess new session tokens and acquire the privileges along with them. crypto/rand implements such a random number generator, including functions that allow you to generate random integers, prime numbers and bytes suitable for this.
Yes, use a crytographic hash. You can use something like gorilla/securecookie to generate a key and provide cookie storage: http://www.gorillatoolkit.org/pkg/securecookie
Note that if you are relying upon the cookie alone for verification that you open yourself up to replay attacks. Use the cookie to trigger a server-side check (user ID == active/valid) or bounce then out if the ID doesn't exist.
Related
Let's consider this use case:
1) I call my API login endpoint with username and password and get my Auth token that I add to every consecutive request to the header as Authorization: Bearer <token>.
2) I call /current-user endpoint with no params, only with Authorization header. Server authorizes user using token and gets user's id from that token. Then he finds the user by id in database and returns it's data.
My question is, whether this approach isn't insecure. I'm wondering, what if I was an attacker and was calling /current-user endpoint using randomly generated tokens. Once I occasionally matched real token, the server would return me other user's data.
Isn't it necessary to store user id on client along with token and call requests using both? Eg. /user?id=<stored user id> with Authorization header and get rid of /current-user endpoint? After that some kind of ACL on server would determine, whether used token has allowed access to user with passed user id.
(I also found there are JWT tokens but I see the same problem there. As an attacker I would somehow manage to guess other user's token and server would return me his data)
For security purposes, it is normally assumed that the user id is known to the attacker anyway. For example, if the attacker already has or knows a legitimate account, she might be able to guess how other user ids are assigned.
Also, if your token is long enough and totally random, it doesn't really make any difference.
Look at it this way: let's say your token has length n, your user id has length m. Without the user id, the attacker has to guess n characters, with it included she has to guess n+m characters. If your n is high enough, you don't need those extra characters. Keep in mind that the effective length of the user id might be much shorter than its apparent length if your user ids aren't completely random, so the m added might actually be really small.
Is it possible for you to use digitally signed tokens? You could basically encrypt the token with the client's (or user's) private key and then encrypt the package along with plaintext userid again with the server's public key. That way only the server can decrypt the package and once decrypted, it knows who the user is. It can then use the public key associated with that userid to decrypt to the package and get the token.
As you havent provided much info on the application and the speed of authentication required or technologies you are using, it is difficult to provide any more info.
I'm building a very basic REST API for my site. The only verb I'm using at the moment is GET which simply outputs a list of posts on my site.
For authentication, I have been reading about HMAC and in particular this article:
http://websec.io/2013/02/14/API-Authentication-Public-Private-Hashes.html
My question centres around what the 'hashed content' should be. As I am not posting any data to the API, I have just been hashing my public key (with a simple salt) using my private key.
Is this a secure method or should I use a different 'content hash'? The data is not sensitive in any way - this was just a learning exercise.
You will want to consider the "replay attacker". When the attacker captures a packet between your API client and the server, what damage can she do when she replays it later?
In your case, if you only use the API key of the user in the HMAC, then the attacker will be able to impersonate that user when she replay the requests. She can call any API request and just set the HMAC to what she captured, as it will validate.
If none of the parameters of the request are included, the attacker will be able to call the request and specify her own parameters. So it's better if the parameters are also included in the HMAC. It doesn't prevent replay of the request with these specific parameters though.
You can include a timestamp parameter to the request and in the HMAC. The server will recompute the HMAC including the timestamp passed in, and it will also verify that the timestamp is recent enough. As the attacker cannot forge new HMAC out of thin air, she will only be able to use ones with matching timestamps that you will reject based on age.
Use Case
I'm building an iPhone app with a simple signup and login.
When a user signs up/logs in, I want the Ruby (Sinatra) server to generate/fetch and return an access token for that user that the iPhone client can then send with every subsequent request using Basic Authentication over HTTPS.
I'm not yet implementing OAuth 2.0 so that third party apps can access the server. Right now, I'm just building a simple, internal API (for my own, first-party, iPhone app).
Example
Basically, I want to generate a secret API key like Stripe's: https://manage.stripe.com/account/apikeys
For example: sk_test_NMss5Xyp42TnLD9tW9vANWMr
What's the best way to do that, say in Ruby?
The Ruby stdlib provides an entire class of secure random data generators called SecureRandom. Whatever you want, you can probably find it there.
Stripe's keys are essentially URL-safe Base64. You can get something very similar like so:
require 'securerandom'
p "sk_test_" + SecureRandom.urlsafe_base64
(Stripe does strip out non-alphanumeric characters, but that's trivial to do with gsub if you don't want hyphens in your keys.)
I recently published a gem called sssecrets (for Simple Structured Secrets) to solve this problem.
Sssecrets is a reusable implementation of GitHub's API token format (which is also used by NPM), and it's designed to make it simple for developers to issue secure secret tokens that are easy to detect when leaked.
Simple Structured Secrets provides a compact format with properties that are optimized for detection with static analysis tools. That makes it possible to automatically detect when secrets are leaked in a codebase using features like GitHub Secret Scanning or GitLab Secret Detection.
Why Use Structured Secrets?
Using a structured format for secrets is really important for security reasons. If you're a developer and your application issues some kind of access tokens (API keys, PATs, etc), you should try to format these in a way that both identifies the string as a secret token and provides insight into its permissions. For bonus points, you should also provide example (dummy) tokens and regexes for them in your documentation.
Here's an example of a bad secret. As of the time of writing, HashiCorp Vault's API access tokens look like this (ref):
f3b09679-3001-009d-2b80-9c306ab81aa6
You might think that this is pretty is a pretty easy pattern to search for, but here's the issue: It's just a UUID string.
While random, strings in this format are used in many places for non-sensitive purposes. Meaning that, given a random UUID formatted string, it's impossible to know whether it's a sensitive API credential or a garden-variety identifier for something mundane. In cases like these, secret scanning can't help much.
What's in a Structured Secret?
Structured secrets have three parts:
A prefix (2-10 characters, defined by you)
30 characters of randomness
A 6 character checksum
That's it!
Here's the format:
[prefix]_[randomness][checksum]
An example Sssecret, with an org of t and a type of k, looks like this:
tk_GNrRoBa1p9nuwm7XrWkrhYUNQ7edOw4GUp8I
Prefix
Token prefixes are a simple and effective method to make tokens identifiable. Slack, Stripe, GitHub, and others have adopted this approach to great effect.
Sssecrets allows you to provide two abbreviated strings, org and type, which together make up the token prefix. Generally, org would be used to specify an overarching identifier (like your company or app), while type is intended to identify the token type (i.e., OAuth tokens, refresh tokens, etc) in some way. To maintain a compact and consistent format for Sssecret tokens, org and type together should not exceed 10 characters in length.
Entropy
Simple Structured Secret tokens have an entropy of 178:
Math.log(((“a”..“z”).to_a + (“A”..“Z”).to_a + (0..9).to_a).length)/Math.log(2) * 30 = 178
See the GitHub blog.
Checksum
The random component of the token is used to calculate a CRC32 checksum. This checksum is encoded in Base62 and padded with leading zeroes to ensure it's always 6 characters in length.
The token checksum can be used as a first-pass validity check. Using these checksums, false positives can be more or less eliminated when a codebase is being scanned for secrets, as fake tokens can be ignored without the need to query a backend or database.
Note that this library can only check whether a given token is in the correct form and has a valid checksum. To fully determine whether a given token is active, you'll still need to implement your own logic for checking the validity of tokens you've issued.
Another note: Because Sssecrets uses the same format as GitHub tokens, you can also perform offline validation of GitHub-issued secrets with SimpleStructuredSecrets#validate.
Further Reading
You can learn more about GitHub's design process and the properties of this API token format on the GitHub blog.
I have been following a couple of articles regarding RESTful web services with WCF and more specifically, how to go about authentication in these. The main article I have been referencing is Aaron Skonnard's RESTful Web Services with WCF 3.5. Another one that specifically deals with HMAC authentication is Itai Goldstiens article which is based on Skonnards article.
I am confused about the "User Key" that is referenced to in both articles. I have a client application that is going to require a user to have both a user name and password.
Does this then mean that the key I use to initialise the
System.Security.Cryptography.HMACMD5 class is simply the users
password?
Given the method used to create the Mac in Itai's article
(shown below), am I right is thinking that key is the users
password and text is the string we are using confirm that the
details are in fact correct?
public static string EncodeText(byte[] key, string text, Encoding encoding)
{
HMACMD5 hmacMD5 = new HMACMD5(key);
byte[] textBytes = encoding.GetBytes(text);
byte[] encodedTextBytes =
hmacMD5.ComputeHash(textBytes);
string encodedText =
Convert.ToBase64String(encodedTextBytes);
return encodedText;
}
In my example, the text parameter would be a combination of request uri, a shared secret and timestamp (which will be available as a request header and used to prevent replay attacks).
Is this form of authentication decent? I've come across another thread here that suggests that the method defined in the articles above is "..a (sic) ugly hack." The author doesn't suggest why, but it is discouraging given that I've spent a few hours reading about this and getting it working. However, it's worth noting that the accepted answer on this question talks about a custom HMAC authorisation scheme so it is possible the ugly hack reference is simply the implementation of it rather than the use of HMAC algorithms themselves.
The diagram below if from the wikipedia article on Message Authentication Code. I feel like this should be a secure way to go, but I just want to make sure I understand it's use correctly and also make sure this isn't simply some dated mechanism that has been surpassed by something much better.
The key can be the user's password, but you absolutely should not do this.
First - the key has an optimal length equal to the size of the output hash, and a user's password will rarely be equal to that.
Second, there will never be enough randomness (entropy to use the technical term) in those bytes to be an adequate key.
Third, although you're preventing replay attacks, you're allowing anyone potentially to sign any kind of request, assuming they can also get hold of the shared secret (is that broadcast by the server at some point or is it derived only on the client and server? If broadcast, a man-in-the-middle attack can easily grab and store that - height of paranoia, yes, but I think you should think about it) unless the user changes their password.
Fourth - stop using HMACMD5 - use HMAC-SHA-256 as a minimum.
This key should at the very least be a series of bytes that are generated from the user's password - typically using something like PBKDF2 - however you should also include something transitory that is session-based and which, ideally, can't be known by an attacker.
That said, a lot of people might tell you that I'm being far too paranoid.
Personally I know I'm not an expert in authentication - it's a very delicate balancing act - so I rely on peer-reviewed and proven technologies. SSL (in this case authentication via client certificates), for example, might have it's weaknesses, but most people use it and if one of my systems gets exploited because of an SSL weakness, it's not going to be my fault. However if an exploit occurs because of some weakness that I wasn't clever enough to identify? I'd kick myself out of the front door.
Indidentally, for my rest services I now use SCRAM for authentication, using SHA512 and 512 bits of random salt for the stretching operation (many people will say that's excessive, but I won't have to change it for a while!), and then use a secure token (signed with an HMAC and encrypted with AES) derived from the authentication and other server-only-known information to persist an authenticated session. The token is stateless in the same way that Asp.Net forms authentication cookies are.
The password exchange works very well indeed, is secure even without SSL (in protecting the password) and has the added advantage of authenticating both client and server. The session persistence can be tuned based on the site and client - the token carries its own expiry and absolute expiry values within it, and these can be tuned easily. By encrypting client ID information into that token as well, it's possible to prevent duplication on to another machine by simply comparing the decrypted values from the client-supplied values. Only thing about that is watching out for IP address information, yes it can be spoofed but, primarily, you have to consider legitimate users on roaming networks.
Being unable to locate a working php/javascript implementation of blowfish, I'm now considering using SHA1 hashing to implement web-based authentication, but the lack of knowledge in this particular field makes me unsure of whether the chosen method is secure enough.
The planned roadmap:
User's password is stored on the server as an MD5 hash.
Server issues a public key (MD5 hash of current time in milliseconds)
Client javascript function takes user password as input, and calculates its MD5 hash
Client then concatenates public key and password hash from above, and calculates SHA1 of the resulting string
Client sends SHA1 hash to the server, where similar calculations are performed with public key and user's password MD5 hash
Server compares the hashes, a match indicates successful authentication.
A mismatch indicates authentication failure, and server issues a new public key, effectively expiring the one already used.
Now, the problematic part is about concatenating two keys before SHA1, could that be prone to some kind of statistical or other attacks?
Is there any specific order in which keys should be concatenated to improve the overall quality (i.e. higher bits being more important to reliability of encryption)?
Thank you in advance.
If you're only using the 'public key' (which isn't actually a public key, it's a nonce, and should really be random, unless you really want it to be usable over a certain timeframe, in which case make sure you use HMAC with a secret key to generate it so an adversary cannot predict the nonce) to prevent replay attacks, and it's a fixed size, then concatenation might not be a problem.
That said, I'm a bit concerned that you might not have a well-thought-out security model. What attack is this trying to prevent, anyway? The user's password hash is unsalted, so a break of your password database will reveal plaintext passwords easily enough anyway, and although having a time-limited nonce will mitigate replay attacks from a passive sniffer, such a passive sniffer could just steal the user's session key anyway. Speaking of which, why not just use the session key as the nonce instead of a timestamp-based system?
But really, why not just use SSL? Cryptography is really hard to get right, and people much smarter than you or I have spent decades reviewing SSL's security to get it right.
Edit: If you're worried about MITM attacks, then nothing short of SSL will save you. Period. Mallory can just replace your super-secure login form with one that sends the password in plaintext to him. Game over. And even a passive attacker can see everything going over the wire - including your session cookie. Once Eve has the session cookie, she just injects it into her browser and is already logged in. Game over.
If you say you can't use SSL, you need to take a very hard look at exactly what you're trying to protect, and what kinds of attacks you will mitigate. You're going to probably need to implement a desktop application of some sort to do the cryptography - if MITMs are going around, then you cannot trust ANY of your HTML or Javascript - Mallory can replace them at will. Of course, your desktop app will need to implement key exchange, encryption and authentication on the data stream, plus authentication of the remote host - which is exactly what SSL does. And you'll probably use pretty much the same algorithms as SSL to do it, if you do it right.
If you decide MITMs aren't in scope, but you want to protect against passive attacks, you'll probably need to implement some serious cryptography in Javascript - we're talking about a Diffie-Hellman exchange to generate a session key that is never sent across the wire (HTML5 Web storage, etc), AES in Javascript to protect the key, etc. And at this point you've basically implemented half of SSL in Javascript, only chances are there are more bugs in it - not least of which is the problem that it's quite hard to get secure random numbers in Javascript.
Basically, you have the choice between:
Not implementing any real cryptographic security (apparently not a choice, since you're implementing all these complex authentication protocols)
Implementing something that looks an awful lot like SSL, only probably not as good
Using SSL.
In short - if security matters, use SSL. If you don't have SSL, get it installed. Every platform that I know of that can run JS can also handle SSL, so there's really no excuse.
bdonlan is absolutely correct. As pointed out, an adversary only needs to replace your Javascript form with evil code, which will be trivial over HTTP. Then it's game over.
I would also suggest looking at moving your passwords to SHA-2 with salts, generated using a suitable cryptographic random number generator (i.e. NOT seeded using the server's clock). Also, perform the hash multiple times. See http://www.jasypt.org/howtoencryptuserpasswords.html sections 2 and 3.
MD5 is broken. Do not use MD5.
Your secure scheme needs to be similar to the following:
Everything happens on SSL. The authentication form, the server-side script that verifies the form, the images, etc. Nothing fancy needs to be done here, because SSL does all the hard work for you. Just a simple HTML form that submits the username/password in "plaintext" is all that is really needed, since SSL will encrypt everything.
User creates new password: you generate a random salt (NOT based off the server time, but from good crypto random source). Hash the salt + the new password many times, and store the salt & resulting hash in your database.
Verify password: your script looks up salt for the user, and hashes the salt + entered password many times. Check for match in database.
The only thing that should be stored in your database is the salt and the hash/digest.
Assuming you have a database of MD5 hashes that you need to support, then the solution might be to add database columns for new SHA-2 hashes & salts. When the user logs in, you check against the MD5 hash as you have been doing. If it works, then follow the steps in "user creates new password" to convert it to SHA-2 & salt, and then delete the old MD5 hash. User won't know what happened.
Anything that really deviates from this is probably going to have some security flaws.