Personal Identity Verification - security

I'm trying to implement two-factor authentication (a token you hold, a password you know).
http://en.wikipedia.org/wiki/Security_token lists many expensive solutions. I need:
Strong encryption.
The ability to programmatically reset the private key on the token (multiple times, if the token is expensive) and read the new private key.
The ability to encrypt a short string (20 characters or less). I believe this means computational power can be very low.
Something cheap. I'd like to ship these tokens to average consumers (think VISA), if possible.
I don't need:
To protect against physical attacks on the token (I assume this is beyond the skill of the average attacker).
To kill the token remotely.
To store any data on the token aside from the private key.
Time-dependent tokens (for fear they will fall out of sync).
I plan on doing the following:
User inserts the token into a PC.
User enters their password on the keyboard.
The token encrypts the password using the private key.
The application sends the result over the network.
The server decrypts the password using the token's public key. If the password matches I let the user in.
I need to make it reasonably difficult for an average programmer/hacker to read the private key off the token. What are my options? If you believe I am setting the bar too low, what do you suggest?

if the audience is consumers then it is quite possible that the computer they use is infected somehow - virus/keyboard logger...
IF that is a possibility then the whole scheme becomes risky because of using the PC keyboard...
Putting aside those concerns:
you could run your own "CA" and generate client certificates - these can be put anywhere (USB stick...) and the application could work with them for verifying the user - by just using the passphrase as password etc. - the beauty of this is: you get for example the ability to revoke certificates etc.
another point:
Depending on how your application communicates with the server you could use this scheme to have SSL connections... SSL standard contains the option not only of authenticating the server but also the client by means of a client certificate...
EDIT:
anything cheap could be read - smartcards would be better but they are not really cheap and the PC needs additional HW to handle them...
Secure but NOT cheap option:
if you want something secure then you need an external smartcard reader with a keyboard, so that nothing sensitive it entered via PC keyboard - but that is not cheap...
another option (cheaper but still secure):
use the mobile as second channel, they login to your app - the app contacts the server, the server generates some unique and time-limited code and sends it via SMS to their mobile and they need to enter that code to complete login process...

"The server decrypts the password using the token's public key"
That doesn't make sense. The point of a public key is that can be public without compromising the security of the system. Perhaps what you meant is that the token contains a public key, and the server stores the private key corresponding to that token?
Security tokens are typically not used in the manner you describe. They are quite commonly used as single sign on (SSO) devices. The token generates a pseudo-random number that is time-dependent. In most cases, the number generated changes every 30 or so seconds. The server is configured with the random seed of the token, so it can generate the same number to verify.
Edit: As per your comment, here's my new suggestion:
Public key on token or client application
Corresponding private key on server
It doesn't matter if the public key is read since knowledge of the public key does not help in guessing the private key
If necessary, change keys at scheduled intervals

Related

Authentication Token for mobile app, is there a offline brute force vulnerability?

from what my understanding is, with token based authentication, a client sends his username/pass and receives a token. and then uses this for auth.
( Background information on my goals so you can better understand what i am trying to do, is simply to use a token to authenticate users on a android app, to the sql database )
Mobileapp - Sends username/pass -> Server / Api
Mobileapp <- sends token - Server / Api
Mobileapp - Uses token to retreive data from server - > Server / api
Mobile app <- sends info - Server / api
in the case of a mobile app, does this token not reside on a users phone?
i think i am misunderstanding a key concept here. but does this not mean that no matter how well we encrypt it, it can be broken in time, and thus our secret key will be revealed? and once the secret key is revealed can the user not generate authentic auth for other users?
Possible solution 1: i was thinking s upon the user signing up, they are given a secret key user for that user, which could be stored with their information on the server instead of a universal secret key, so even if it is broken it will not work for other users, is this how people go about preventing this type of thing?
solution 2 or combined with one, would be to make each users key expire after 24 hours, and make encryption on the key that would take at least 24 hours to break, to provide a decent level of security? however the problem with this is the users password would need to be stored somewhere, which opens the problem of it being brute forced anyway.
please excuse my ignorance, ANY and all help is appreciated :)
A token is derived from some information and a private key. Getting the private key from that token is as likely as getting the private key from the corresponding public key (very unlikely if the key material is correctly created). And in order to forge a token, you need the private key. To sum it up, if you derive the token correctly, an attacker will only be able to use the token for as long as it is valid, not forge another, and not get your private key.
The attacker cannot obtain the Private Key from cracking the token stored in the device. It is not about time, it's just not possible.
The token can be stored in the device if you're planning to provide a longer session active period. but I'd recommend to expire it after 24 hours at least. Otherwise, you don't need to store the token in the device if you're planning to maintain the session active for 15 minutes, lets say. You could instead save the token in memory and expire it when:
User signs out
After 15 minutes of user inactivity
When user closes the application
Keep in mind that in order to harden security, it is recommended Not to use concurrent sessions (multiple active tokens per user). It's recommended to expire all remaining active sessions (tokens) every time the user issues one. And yes, this means that user needs to enter credentials every time. It's not recommended to store the user's password on the device. However, you can store the user's username with the user's consent of course.

REST Web Service authentication token implementation

I'm implementing a REST web service using C# which will be hosted on Azure as a cloud service. Since it is a REST service, it is stateless and therefore no cookies or session states.
The web service can only be accessed over HTTPS (Certificate provided by StartSSL.com).
Upon a user successfully logging into the service they will get a security token. This token will provide authentication in future communications.
The token will contain a timestamp, userid and ip address of the client.
All communication will only happen over HTTPS so I'm not concerned about the token being intercepted and used in replay attacks; the token will have an expiry anyway.
Since this is a public facing service I am however concerned that someone could register with the service, login and then modifying the token that they receive to access the accounts of other users.
I'm wondering how best to secure the content of the token and also verify that it hasn't been tampered with.
I plan on doing the following to secure the token:
The client successfully logs into the service and the service does:
Generate a random value and hash it with SHA256 1000 times.
Generate a one-time session key from private key + hashed random value.
Hash the session key with SHA256 1000 times and then use it to encrypt the token
Use private key to sign the encrypted token using RSA.
Sends the encrypted token + the signature + the hashed random value to the client in an unencrypted JSON package.
When the client calls a service it sends the encrypted token and signature in an unencrypted JSON package to the service. The service will
Recreate the session key from the private key + the hashed random value
Use the private key to verify the signature
Use the hashed session key to decrypt the token
Check that the token hasn't expired
Continue with the requested operation...
I don't really know anything about encryption so I have some questions:
Is this sufficient or is it overkill?
I read that to detect tampering I should include an HMAC with the token. Since I am signing with the private key, do I still need an HMAC?
Should I be using Rijndael instead of RSA?
If Rijndael is preferred, is the generated IV required for decrypted? i.e. can i throw it away or do I need to send it will the encrypted token? e.g. Encrypted Token + HMAC + IV + hashed random value.
Since all communication happens over HTTPS the unencrypted JSON package isn't really unencrypted until it reaches the client.
Also I may want to re-implement the service in PHP later so this all needs to be doable in PHP as well.
Thanks for your help
You are really over-thinking the token. Truthfully, the best token security relies on randomness, or more accurately unpredictability. The best tokens are completely random. You are right that a concern is that a user will modify his/her token and use it to access the accounts of others. This is a common attack known as "session stealing." This attack is nearly impossible when the tokens are randomly generated and expired on the server side. Using the user's information such as IP and/or a time stamp is bad practice because it improves predictability. I did an attack in college that successfully guessed active tokens that were based on server time stamps in microseconds. The author of the application thought microseconds would change fast enough that they'd be unpredictable, but that was not the case.
You should be aware that when users are behind proxy servers, the proxy will sometimes view their SSL requests in plain text (for security reasons, many proxies will perform deep packet inspection). For this reason it is good that you expire the sessions. If you didn't your users would be vulnerable to an attack such as this, and also possible XSS and CSRF.
RSA or Rijndael should be plenty sufficient, provided a reasonable key length. Also, you should use an HMAC with the token to prevent tampering, even if you're signing it. In theory it would be redundant, since you're signing with a private key. However, HMAC is very well tested, and your implementation of the signing mechanism could be flawed. For that reason it is better to use HMAC. You'd be surprised how many "roll your own" security implementations have flaws that lead them to compromise.
You sound pretty savvy on security. Keep up the good work! We need more security conscious devs in this world.
EDIT:
It is considered safe to include timestamps/user IDs in the token as long as they are encrypted with a strong symmetric secret key (like AES, Blowfish, etc) that only the server has and as long as the token includes a tamper-proof hash with it such as HMAC, which is encrypted with the secret key along with the user ID/timestamp. The hash guarantees integrity, and the encryption guarantees confidentiality.
If you don't include the HMAC (or other hash) in the encryption, then it is possible for users to tamper with the encrypted token and have it decrypt to something valid. I did an attack on a server in which the User ID and time stamp were encrypted and used as a token without a hash. By changing one random character in the string, I was able to change my user ID from something like 58762 to 58531. While I couldn't pick the "new" user ID, I was able to access someone else's account (this was in academia, as part of a course).
An alternative to this is to use a completely random token value, and map it on the server side to the stored User ID/time stamp (which stays on the server side and is thus outside of the clients control). This takes a little more memory and processing power, but is more secure. This is a decision you'll have to make on a case by case basis.
As for reusing/deriving keys from the IV and other keys, this is usually ok, provided that the keys are only valid for a short period of time. Mathematically it is unlikely someone can break them. It is possible however. If you want to go the paranoid route (which I usually do), generate all new keys randomly.

Storing the OAuth credentials from DropBox securely in a Database for later use

I am building a web app which will use the DropBox API to save data to a users folder. There are 2 parts to the site: an ASP.NET MVC Front End and a Windows Service. At the moment, I was planning on dumping the oauth string and user Id from the authorisation request to database, and use that in both the service and website calls, but how should I store that information? Should I encrypt it or not? And if so, any recommendations on how? For example, if the database is encrypted, how do I store the Encryption key?
Do you want to always have access to the user's drop box account or only when they are loged in to your system ? I assume the former since you want to store the o-auth token. In that case see the encryption discussion below for why you can't really encrypt it. I'd suggest however, that you take the safer route and only access drop box either when the user is loged in or shortly their after (i.e. don't store persistent auth tokens )
The secure approach
When the user logs in, get an oauth token from the dropbox, use it to perform whatever actions they want and if necessary keep it around after the log out to keep doing tasks ( background sync or something). However, once that last task finishes, delete the token. This means that if your server is compromised only the loged in users or those that recently loged out are exposed. Its a mitigation, but its the best you can get.
I believe you can do this with o-auth without explicitly prompting the user for a new token every time. If not, I know you can do it with opendID, though I could see drop box not allowing that.
Finally, if neither of those works, you could store the o-auth key persistently encrypted under a key derived from the users password with say PBKDF2(with like 5000 iterations). When they log in, you decrypt it, use it, and then delete the cleartext copy. The downside to this is 1) password resets require a fresh o-auth token since you no longer have their key and 2) the user must log into your site itself and give you a password so you can derive the key. They cannot use openid.
Encryption
If you want continual access to the oauth tokem you can't really do meaningful encryption. As you said, where would you store the key ? For a web service, there is no good answer. For an end user system, the answer is derive the key from the user's password which you the must not store(this is what lastpass does). You can't do this because you want to have access to the data even when the end (wepapp) users are not loged in.
Ok, what about the sysadmin's password? Well since the server is running all the time, this is worthless since a compromise would still reveal the keys. Worse, reboots would take down your app because it needs the sys admin's password to decrypt its data and they are not likely their when the system crashes at 3am.
They make Hardware Security Modules that store keys and perform crypto operations with them, so an attacker could get the key because it never leaves the HSM. However, an attacker could just ask the TPM to decrypt the o-auth string. The best you could do was rate limit this so an attack could only get like 1000 tokens an hour (obviously that rate needs to be larger that legit usage). Given that HSMs are expensive and make hosting expensive because you need a dedicated system, this is not worth it.
In an ideal world, you'd use a TPM to hold the keys and have it only release the data if the system is not compromised. Unfortunately, TPM's currently only support verifying that the correct program (e.g. the boot-loader,then kernel, then user land program) was loaded. They do nothing if that program is compromised after it is loaded, which is the threat vector here. This might change in the next 5 to 10 years, but that does not help you now.

How should I savely store encrypted user data on my server, and serve it only to the right user?

Let's assume I must store user's sensitive data, which was optionally encrypted on the client side.
Encryption (optional) should be done with user's passphrase.
User login (optional) should be done with user's password.
Notes:
A plain-text password is not stored on the server or transferred over the network.
My options and their drawbacks:
1. No authentication, Client-side authorization:
The server gives the data to everyone, but only the original user have the means to decode.
Data can be used by anyone to try to crack the encryption - not the best way to secure it.
2. Server-side authentication, no authorization:
Server stores user's password to access the data, and only gives the data to the user that can provide the right password.
Users don't trust the network for transferring their data without encryption.
3. Authentication and authorization:
Server stores user's password to access the encrypted data, the encryption is done using the passphrase that is different from user's password.
Good security, but users don't want to remember two passwords.
4. Authentication vs. Authorization:
Server stores user's password to access the encrypted data, the encryption is done using the same password.
Users are happy. Some security concerns.
I prefer the latest fourth option, but my concern is:
What if the server will get compromised, how can I be sure that encrypted password and encrypted data can't be used together to break the encryption?
How can I make it harder to break the encryption?
Some thoughts:
Use different encryption algorithms for password and data.
Add fixed string to the end of the user's password before encryption.
Pad user's password to some length.
EDIT:
The system should be very similar to a backup system that should be secure from all sides: the server should not be able to read the data, only the original client should be able to access the data and man in the middle attacks should be prevented. So if someone hacks the server authentication or the client encryption, the data should not be revealed.
It should be web based, so the man in the middle attack should be prevented with HTTPS.
To prevent server hacks revealing the data, the data is encrypted in client-side.
To prevent client encryption tampering, the access to the data should be protected on the server side with some log in and password or a token (may be unique URL).
#Vitaly, permit me to clarify some terms before I answer, as you seem to be using a different meaning for some than is commonly used.
Authentication - the process of proving who you are (more accurately, that you own the identity you are claiming).
Authorization - the mechanism used to restrict, control, and grant access.
Encryption - a mechanism for protecting data, even from someone who has access to it.
Now, allow me to rephrase your options, and then I'll suggest something else:
No Authentication, No Authorization, Client-side encryption
Server-side authentication, Server-side authorization, Server-side encryption
Server-side authentication, Server-side authorization, Client-side encryption
Server-side authentication, Server-side authorization, Client-side encryption using server credentials.
Now, I think it can be clearer where each one stands.
In general, you really want to follow the "best practice" (dont get me started on those) principle of "Defense in depth", i.e. dont use only encryption, or only access control, instead use both! But, as you pointed out, this can be in contrast (if the user is required to remember TWO passwords) to another principle, "Keep Security Simple".
Without trying to be TOO annoying, you didn't give much information in the way of your environment. For example, is this e.g. a Web application? If so, why is SSL/TLS not enough encryption for you? Or is this a question of users uploading personal data that you (and your system) should not see either (e.g. a backup-type service)? In which case client-side encryption would be necessary...
So, (finally) my proposed options, depending on your environment / requirements:
If you can, rely on secure protocols (e.g. SSL/TLS) for encryption. Use server-side authentication + authorization, protocol encryption.
If your system needs to further protect this data, e.g. credit cards (note that I am not currently a PCI:QSA ;) ), use the previous option, and in addition server-side encryption using a server-generated encryption key (NOT the password) (and of course protect that).
If the data needs to be protected FROM your system, you will need to do client-side encryption IN ADDITION to server-side authentication+authorization (your option 3 as I restated it).
However, you don't necessarily need to force the user to remember an additional password/phrase. Again, depending on your environment, you might be able to consider some form of key stored on the client, e.g. a certificate in the user's certificate store / keyring, or even stored in a protected configuration file; a key based on biometric data (not easy but i've seen this done successfully, though it has its own set of issues), out of band key distribution (e.g. via cellphone), etc. This would enable you both to use strong keys, prevent the server from accessing those keys, not require the user to remember two keys, and doesn't re-use a single password for different usages in different contexts.
You could take a look at zero-knowledge protocols for authentication, in particular to the Secure Remote Password protocol, which makes it possible to perform password-based authentication without revealing the password to the server. This way the same password can be used both for authentication and for deriving a data encryption key.
Also, you could take a look at the Clipperz online service, which implements something similar to your needs and is also open source.
Use option one and make the URL for the data contain a long random string. Anybody who knows the random string can get the data. Of course, only the client who created the data is going to have that URL right off.
If someone wants to give someone else revokable access, allow them to generate a new random URL and provide a means for them to name that random URL and revoke its ability to get at the data.
Capability based security is easier to get right, more flexible and makes more sense to users. There is a really excellent YouTube video about capability based security and a nice website with some essays about it.

Cross-Application User Authentication

We have a webapp written in .NET that uses NTLM for SSO. We are writing a new webapp in Java that will tightly integrate with the original application. Unfortunately, Java has no support for performing the server portion of NTLM authentication and the only library that I can find requires too much setup to be allowed by IT.
To work around this, I came up with a remote authentication scheme to work across applications and would like your opinions on it. It does not need to be extremely secure, but at the same time not easily be broken.
User is authenticated into .NET application using NTLM
User clicks link that leaves .NET application
.NET application generates random number and stores it in the user table along with the user's full username (domain\username)
Insecure token is formed as random number:username
Insecure token is run through secure cipher (likely AES-256) using pre-shared key stored within the application to produce a secure token
The secure token is passed as part of the query string to the Java application
The Java application decrypts the secure key using the same pre-shared key stored within its own code to get the insecure token
The random number and username are split apart
The username is used to retrieve the user's information from the user table and the stored random number is checked against the one pulled from the insecure token
If the numbers match, the username is put into the session for the user and they are now authenticated
If the numbers do not match, the user is redirected to the .NET application's home page
The random number is removed from the database
1) Having a pre-shared key stored in a file (even a program file) is theater and not security.
2) Your tokens (random numbers in the database) should be set to expire. I suggest expiring after one attempt, but a time limit should be set too. Otherwise you could end up with thousands of leftover tokens that provide access with the right guess.
3) If all you need to do is verify from the Java tool that access is permitted, you can use public key cryptography and not pre-shared keys. That way you only need to protect the private key. Of course, protect includes: "don't put it in a file accessible by the user you are protecting it from," and without that protection, this approach is no different from pre shared keys.
4) It seems ot me that the java tool could be easily modified to ignore the authorization step and just perform whatever sensitive task you are trying to protect.
Take all of this with a grain of salt, as I know relatively little about Java and .NET. I do know a bit about cryptography though.

Resources