I recently stumbled across this article on securing Web API endpoints.
If I'm using SSL, is there any advantage to encrypting the user string in the header? What are the risks if I include the user key (Id) as plaintext instead of ciphertext?
TLS is transport-level security. I.e. the data is not secured by TLS before the data reaches the transport and after that. If your data is long-term and/or you keep them elsewhere besides using during the transport session, then it might make some sense to keep them encrypted (and then transfer them encrypted if possible). If your data lifetime is short and the data makes sense only during the transport session, then there's no much sense in encrypting the data besides TLS.
The author of the article is basically combining the concepts of a user identifier and a user secret into a single cryptographic token. If you choose to send a user identifier in plaintext instead, then that user identifier must be kept secret (just as the token must be kept secret). As long as that secrecy is maintained there is no advantage to using the token.
Note that this system doesn't seem very secure as presented. If an attacker can guess a valid user identifier then they can generate a valid token. The author is basically using RSA as a glorified hash function. I'd recommend you look for another reference.
Related
I wanted to use encrypted local PASETO tokens for the Request Object in the OIDC, but it turns out that I need to store the key somewhere to decrypt this request object, and it must be available unencrypted/unhashed as it will need the Request Object to decrypt. So I will have to store it as plain text in a database? Pretty dangerous. So I started to wonder how JWE works, but the documentation from https://datatracker.ietf.org/doc/html/rfc7516#section-5.1 about JWE encryption is quite confusing for me. Does JWE solve this problem of storing a symmetric key in a database as plain text or does it have other ways?
There are a few different solutions here, which solve different problems:
ENCRYPTED JWTs
These can be used when the app wants to prevent information disclosure. They are issued by the Authorization Server, which uses a public key to encrypt them. There is then a burden on the app to maintain a private key to decrypt them. See the Encrypted ID Tokens for some example usage.
REQUEST OBJECTS
These are often used to protect against man in the browser tampering. The app only needs to deal with public keys, which it already has access to, so the solution is easier to manage. Newer standards such as PAR and JARM are used, as in this summary.
JWT INFORMATION DISCLOSURE
If you want to avoid revealing sensitive data in access token JWTs, then the usual technique is to return only opaque access tokens to internet clients. This is easier to manage than encryption. See the Phantom Token Pattern for how this works.
SUMMARY
I would usually avoid introducing key management into apps. Aim to manage this in the Authorization Server instead.
We are currently implementing our authorization to a restricted resource by encrypting specific information and the password given to create a token using AES/CBC/PKCS5Padding encryption with a 128bit private key known only to the server.
Inside this token we place
hash of password(sha-512 and a random salt of 64 bytes)
expiry date
valid flag (boolean)
creation date timestamp
The server then encrypts this information using its private key and passes it to the client.
The client requests the restricted resource and presents this token to the server which decrypts it and validates the contents to provide access to a restricted resource.
We wish to do it this way to avoid keeping information regarding issued tokens on our server to avoid potential resource limitations.
Since I am not a security expert any help showing possible vulnerabilities or why this is a bad idea would be much appreciated.
Just send the hashed version for comparison.
Just using a hash function is not sufficient and just adding a salt does little to improve the security. Instead iterate over an HMAC with a random salt for about a 100ms duration and save the salt with the hash. Use functions such as PBKDF2 (aka Rfc2898DeriveBytes), password_hash/password_verify, Bcrypt and similar functions. The point is to make the attacker spend a lot of time finding passwords by brute force. Protecting your users is important, please use secure password methods.
See Toward Better Password Requirements by Jim Fenton.
[DRAFT NIST Special Publication 800-63B Digital Authentication Guideline](
https://pages.nist.gov/800-63-3/sp800-63b.html)
NIST’s new password rules – what you need to know:
https://nakedsecurity.sophos.com/2016/08/18/nists-new-password-rules-what-you-need-to-know/ by Sophos
I am planning to use cryptosupport API to encryp/decrypt certain cookie keys bearing PCI/PII customer data. I am setting/reading these cookies at both client and server side. At server end (java), I am able to call API and encrypt/decrypt. How do I call the API from clientside (javascript) ? The usage is quite huge at clientside and I dont want to make ajax calls to server.
Is it advisable to use this API with requirement of encrypting cookie data used at both client and server side?
Or is there simpler encryption API for this purpose?
It is a server-side AEM capability only.
And think about it--if you were able to call an API to decrypt a cipher on the client side (JavaScript), what security would it provide? End users could easily also decrypt the cipher and see the secret, so it really would defeat the purpose of having an encrypted secret.
See What encryption algorithm is best for encrypting cookies? which says
Since this question is rather popular, I thought it useful to give
it an update.
Let me emphasise the correct answer as given by AviD to this question:
You should not store any data that needs encrypting in your cookie. Instead, store a good sized (128 bits/16 bytes) random key in
the cookie and store the information you want to keep secure on the
server, identified by the cookie's key.
I'm currently researching cross-domain SSO implementations, and I may not be able to use a third party SSO provider.
I found a custom implementation online that involves a series redirects and an encrypted querystring parameter.
MrUser logs into http://www.foo.com
MrUser clicks a link to http://www.bar.com/page.aspx
MrUser is not authenticated on bar.com, but bar.com has authentication code that redirects to http://www.foo.com/sso.aspx
The sso.aspx page checks for a valid ASP.NET authentication cookie in the cookies collection. If it exists, sso.aspx redirects to http://www.bar.com/page.aspx&ssoauth=[encryptedkey] (where [encryptedkey] is an MrUser's encrypted id that foo.com and bar.com have agreed on). If there is no valid ASP.NET authentication cookie, then it just redirects without the ssoauth parameter.
Bar.com does a check to avoid an infinite redirect loop and then decrypts the ssoauth value. If there is no ssoauth parameter, then MrUser is redirected to the login page, otherwise Bar.com uses the decrypted id to authenticate MrUser before it sends him on to page.aspx.
What are the potential security issues (or other types of issues) with this method?
(cite: http://blogs.neudesic.com/blogs/michael_morozov/archive/2006/03/17/72.aspx)
Edit: In response to the answers citing that the encrypted id is the same every time, and an attacker could use it to gain access - What if bar.com checks the referrer so that it only accepts ssoauth parameters from foo.com?
The first issue is that any encrypt/decrypt scheme can be figured out when it's plainly visible. You'd be better of implementing something more along the lines of a PKI encryption/decryption platform where the encryption keys are public but the decryption keys are private. The encryption will need to be suitably complex in order to increase the "time to crack", and that will require resources to perform encrypt/decrypt of the key.
The fact that you have a non-common domain will create the need to supply the encrypted piece in the header (either post or get), and pass it in plaintext. While querystring information is kept secure for the lifetime of the request (edit: assuming SSL), it is not secure from a browser history (making it accessible to common-use computers).
The worst security problem is the concept of "crack one/crack em all". If one of the servers is compromised and its encryption/decryption algorithms, salt, etc are exposed, it would be possible for an attacker to compromise all systems by generating valid encrypted SSO keys at will and on demand.
None of these problems is terribly tragic. I wouldn't implement this scheme at a bank or a medical establishment, but for a low risk site like SO or Twitter it would be perfectly acceptable. It will all come down to managing resources, risk, and gain.
Anyone can use encryptedKey to gain access as MrUser. Rather than encryption, a signing or message authentication service is needed. The authenticated message should include a nonce with the user identifier to prevent replays.
Protocols like this are hard to devise. Even TLS, which was widely used and reviewed for years has security flaws. Don't try to use an unproven authentication mechanism.
A potential problem is if ssoauth encrypted key is only the User's encrypted ID. Such a setup will result in providing the same key each time, which can therefore be both reused, by original user or worse by a third party.
One way to avoid this situation is to keep the time-of-day clocks of foo.com and bar.com servers relatively synchronized and to issue keys which include the date/time (modulo 5 minutes).
People are often tempted to use the web client's IP address as one of the elements of this encryption, but this is a bad idea, for several proxies and gateways use different public IPs within their pools to access different domains/servers.
Another way to allow for a distinct password each time is to have bar.com's redirect to
http://www.foo.com/sso.aspx
include a parameter such as
http://www.foo.com/sso.aspx?ParamForKey=some_random_number
and to use ParamForKey as part of the encryption process
There are several issues:
1) How long is the encrypted token valid? It should be valid only for a couple of seconds. Easy if all servers are on ntp. Having expiry also protects user in case they have the link containing encrypted token is left around. Validating nonce is difficult if you have many bar.com servers - you could say that having an expiry of a couple of seconds should mitigate replay.
2) Problem with SSO cross domain is single sign off. What if users sign off foo.com. The session on bar.com must be invalidated. You could XSRF bar.com logout as a hack :). You should have bar.com beacon foo.com every 15 minutes to see if user is still logged in.
3) What if user does not sign off bar.com and it is a multi-user computer and another user signs onto foo.com? You have to ensure that you if userids do not match previous user's data is not shown.
4) As someone else mentioned, you probably want a signature or HMAC on userid rather than encryption. If you do encrypt, remember to protect the integrity of the ciphertext. You do not want user A flipping bits in ciphertext to see if they can access User B's data on bar.com.
I would have the redirect over https.
Finally, as everyone said, referrers can be spoofed. Don't trust them.
I often make small websites and use the built in ASP.NET membership functionality in a SQL Server database, using the default "hashing" password storage method.
I'm wondering if there's a way to authenticate a user by hashing his password on the client and not sending it in clear text over the wire without using SSL.
I realize that this would only be applicable for users with Javascript enabled.
Or... possibly, this would be a great built-in capability for Silverlight (is this in the Silverlight roadmap?)
EDIT:
I'm also looking for "degrees of security." Meaning, if there is a method that has some advantages over simply sending plaintext password, I'd like to know what they are and why.
I know there are lots of people who do small sites with logins (such as a family website or volunteering to make a site for a local cooking club) and don't see the need for purchasing SSL certificates.
This is possible. This is actually what Kerberos authentication does, only with a little bit of added spice. To ensure that your authentication mechanism is secure, you need the following:
A common hashing algorithm on both the client and server.
A one-time salt value generated on the server and shared with the client.
The original password stored in a database.
To securely authenticate a user via hash code, so you avoid sending the actual password across the wire, first generate a random, single-use salt value on the server. Send this salt value to the client, and generate a hash code from the salted version of the password the user has input. Send the resulting hash code to the server, and compare it with a hash code generated from the salted version of the stored password. If the comparison fails, discard the salt, regenerate a new salt value, and repeat the process.
The reason for the single-use salt is to prevent anyone listening to the conversation from capturing the hash code of the users password, which, when you use hash code comparison, is just as good as having the password itself.
Note that you need to keep the original password around, you can't hash it once on the server and save the hash in the database. If you need to ensure that the passwords stored in your database are also secure, then you will need to encrypt them before storing them. I believe that ASP.NET membership providers do allow you to store passwords encrypted, however, if you really wish to have a secure authentication mechanism that is difficult for a hacker to crack, then I would recommend handling password storage and retrieval entirely on your own.
Finally, I should note, that such a complex password transfer mechanism should be largely unnecessary if you use SSL to encrypt your connection during authentication.
References (for those who have never heard of Kerberos or SRP):
http://en.wikipedia.org/wiki/Kerberos_(protocol)
http://en.wikipedia.org/wiki/Secure_remote_password_protocol
This is a bad idea, security wise. If you send a non-ssl form that contains the hashed password, then anyone capturing traffic has all they need to login. Your javascript has to result in something that indicates success (a redirect, token passed to the server, etc). Whatever it is, the listener now can recreate that without proper authentication.
SSL was built for a reason, by people who tried a lot of other web authentication schemes. It is far safer and cheaper to get a cert than to try write your own safe authentication scheme that works without encryption.
Added for clarity:
Client side hashing alone is not safe. Say I have a form with the following inputs
<form action="signin.whatever" method="post">
<input type="text" id="txtUser">
<input type="text" id="txtPass">
<input type="hidden" id="hiddenHash">
<input type="submit" onclick="hashAndSubmit()">
</form>
where hashAndSubmit() hashes the password and puts it in hiddenHash, and blanks out the password field. If I sniff your submission and see the following fields:
txtUser:joeuser
txtPass:
hiddenHash:xxx345yz // hash result
that's all I need as an attacker. I build a form with your user and hash value and I'm all set. The password is not necessary for a replay attack.
To get around this, you have to look at one-time salt values, or other schemes. All of which introduce more cost(don't forget developer time) and risk than SSL. Before you do something like this, ask one question...
Do I trust myself more than years and years of public testing of the SSL encryption?
You could do this, but it would be just as insecure. The problem is that someone could capture the hash and replay it (just as they could the original password). I suppose you're providing some protection against the exposure of the actual password (in case they use it on other systems), but your system will be no more secure.
You can implement your hashing algorithm client side (in javascript) and send only the user name and hash result over the wire. Note that in order for this to be secure the hash must be salted with a string provided by the server, and the string must be unique for every request. The sever still needs to check whether the hash is correct or not and authenticate the session.
At least you have to use a salt for generating the hash. Otherwise the hash value is as "valuable" as the plain password when intercepted - at least on your site.
You can send as post fields the username/realm/password hash following the HTTP Digest protocol. AFAIK there is no built-in client component nor server side component to generate/validate this so you have to do everything manually. It also requires your storage to store a specific hash format, see Storing password in tables and Digest authentication
The advantage is that you're following a well analyzed and understood authentication protocol. Don't roll your own.