First time doing a secure login from a mobile app to a server (built in java). I want to understand if I got this right.
Login in for the first time:
1. On the mobile device hardcode a security phrase (ex: "superSecurePhrase##!!".
2. Take in a username and password.
3. Use base64 to encode username+phrase and password+phrase.
4. Using https send this information to my server.
5. On the server decode using base64 with the matching phrase hardcoded on the device.
6. Hash password and save to DB, also hash username and save to DB.
7. Use AES algorithm to create a session token
8. Send session token to device.
9. Save session token to DB, and when user requests something, make sure they match.
To verify credentials it is pretty much the same process except username and password aren't saved, but instead queried for the DB and checked for a match?
Is this the general pattern used for this kind of thing?
Potential vulnerabilities:
1. Physical access to the device to retrieve the hard coded base64 phrase?
2. SSL Sniffing and acquiring the token?
Thank you for your help.
If I were on your place I would hash the password with SHA-1/SHA-2 on the device when registering. This way I will be sending only the hash. If the request is intercepted by a man in the middle, even if they decode the Base64 encoded string, they will have only the hash. As an end use I will be terrified if someone has my raw password, because I use it on other places (I know it is a bad practice). You can still Base64 encode the hash with the salt.
You can use your "superSecurePhrase##!!" to salt your password string during the SHA-1/2 encoding, or have a separate salt for this.
The token should be random on every generation (it stays the same until it expires), I would use something like the org.apache.commons.lang.RandomStringUtils, assuming you are using Java on the backend.
On the app side I would store the token in the shared preferences, if the device isn't rooted, it isn't accessible by other apps. If it is, and the user allowed root access to the app, you can't do anything about it. Storing in a databes is also OK, if you are already using a database in the app.
So, to sum it up, the biggest difference is that I would prefer to create the password hash on the device and send only the username and the hash over SSL.
Related
I have a program where the username and password is hard coded. So I want to pass that Executable JAR file to colleagues working in the same network. I want to secure the Password and don't want to reveal it to anyone. Is there a way where I can pass on the JAR File and keep my password secure without anybody coming to know about the password.
Maybe if there is a way of storing some password in a file and keeping it on a server and every time, the JAR file tries to run, it picks up the pass from the remote file?
Your headline and the content of your question are somehow contradicting. A hardcoded password ain't secure in the very first place.
I would recommend a different design: create some kind of service that allows access without a password; for example based on the network address of the client. That service would then be the only piece that really needs to know this password. And come the day that have to change something (like the password, or the actual software you are using) ... there will be only one thing you need to change.
Meaning: configure your JAR to trigger some RESTful service for example ... which in turn internally calls whatever application needs that username/password.
You could use a salted hash (hashing a random number + the password). It would ask them for a password and would hash the password and salt and compare it to the stored one. This is very weak security but is at least better than comparing it to a hardcoded password.
The hash function should be cryptographically secure, like SHA256. If you're not familiar with cryptographic hashes, it takes data of any size and mangles it down to a small fixed size fingerprint (MD5 is 128 bits, SHA1 is 160 bits, SHA256 is 256 bits, etc)
Here are examples of md5:
md5("abc"): 900150983cd24fb0d6963f7d28e17f72
md5("not secure"): 116e54e126621ed4070b2f30ebc07fec
So instead of storing the password "not secure" in your file, store the hash "116e54e126621ed4070b2f30ebc07fec" instead.
I need to encrypt a string at client side and send it to the server.
Once there I need to decrypt it.
Is the Using Password-Based Encryption the best solution?
I need it because I have a voting mechanism, where I send ajax posts to vote an entry.
This mechanism use the Facebook id from the current user. My goal is to encrypt the FB id from client side to avoid that they hack it by sending requests with differents ids.
If a second post with the same id is sent I will block the vote.
Once the id is decrypted I will check if it is a real FB user using the graph.
Javascript encryption won't help here. Any good detective/hacker can see how it's all done on the client and see what the data was before it was encrypted and see how it's encrypted.
The only way to prevent a user from voting multiple times is to have the vote tied to an account or token that you can both verify on your server and tie to a particular user that isn't easy for the user to make lots of different accounts. In general, you probably can't stop this entirely, but you can make it enough trouble that most won't do it by making it require enough steps (including some sort of captcha so it can't be automated).
SSL will protect client/server communications, but won't do anything to stop the client from doing things you don't want them to do.
“Encryption” does not make any sense here as you have already been told (because the value that would be encrypted client-side could be manipulated before you encrypt it), and SSL does of course not solve this problem either.
Send the access token of the user to the server instead. And then either make a request for user data with it (/me), or debug it – then you will know that the request is genuine, because a user can not “fake” an access token for another user.
Considering that there is no authentication an HTTP fingerprint can be used to check if requests with different userId come from the same user.
Fingerprint will be create from HTTP request data like:
-user agent
-language
-IP
-charset
and other data present in the http request.
In my application, users create data then use their secret key to calculate a hash. The data with the appended hash are sent to the server.
The server recalculates the hash using the private key it has listed for the user.
Now, on the server's side, I obviously can't store the secret key in plain-text. However, I also can't do a one way store using Hmac, because then, when I recalculate the hash on the data, it will give a different response.
What is the best way to store user's secret password on the server side?
The best way is what you are doing now. I mean the password is never stored either as plain text nor in encrypted reversable form. I did not exactly understand your problem but if you want to make the system truly secure find solution for your problem without using user's password in plain form.
But if you indeed need this I'd recommend you at least to store passwords in DB encrypted. The encryption password should be also hidden somehow to make potential hacker's work harder. But note: once you do it the system becomes breakable and all depends only on the hacker's professional skills and motivation.
I would like to compare a String to the password of the currently authenticated user (encrypted keys comparison). It seems like retrieving password from the ticket cache but how can I do that?
Thank you
It is not possible to retrieve the password from information that are available on the client or anywhere in a kerberos system. According to the kerberos article in wikipedia (which holds similar information to what I read at other sources) the user entered password is hashed with a one-way function into something that serves as the secret from this point on. The secret is available at the key distribution center (KDC) and the ticket granting ticket (TGT) is symmetrically encrypted with this secret. To receive and use the TGT, a client has to provide the secret to decrypt the package - which is done by asking for the password from the user. After doing so, the TGT is decrypted and is saved in the ticket cache.
The TGT itself has parts encrypted with a secret only the kdc knows, it does not hold the password of the user. As, for example, this article from 2000 explains, the password is not stored in the ticket cache either - just parts from the TGT. From my understanding it is not possible, to check the user password using the ticket cache.
You might want to write your own CallbackHandler to somehow reuse or provide the credentials programmatically, but from my understanding this might lead to security problems.
You might want to think about solving your problem with a total different approach, but there is to little information to suggest any other solution.
I don't know if that's intended to be possible. That hash may be salted with a key known only to the server. What I'd try instead is to just authenticate using the user's id and the given String. If the server accepts the authentication request, the password was valid.
We recently had a security audit and it exposed several weaknesses in the systems that are in place here. One of the tasks that resulted from it is that we need to update our partner credentials system make it more secure.
The "old" way of doing things was to generate a (bad) password, give it to the partner with an ID and then they would send that ID and a Base 64 encoded copy of that password in with all of their XML requests over https. We then decode them and validate them.
These passwords won't change (because then our partners would have to make coding/config changes to change them and coordinating password expirations with hundreds of partners for multiple environments would be a nightmare) and they don't have to be entered by a human or human readable. I am open to changing this if there is a better but still relatively simple implementation for our partners.
Basically it comes down to two things: I need a more secure Java password generation system and to ensure that they are transmitted in a secure way.
I've found a few hand-rolled password generators but nothing that really stood out as a standard way to do this (maybe for good reason). There may also be a more secure way to transmit them than simple Base 64 encoding over https.
What would you do for the password generator and do you think that the transmission method in place is secure enough for it?
Edit: The XML comes in a SOAP message and the credentials are in the header not in the XML itself. Also, since the passwords are a one-off operation for each partner when we set them up we're not too worried about efficiency of the generator.
Password Generation
As far as encoding a password for transmission, the only encoding that will truly add security is encryption. Using Base-64 or hexadecimal isn't for security, but just to be able to include it in a text format like XML.
Entropy is used to measure password quality. So, choosing each bit with a random "coin-flip" will give you the best quality password. You'd want passwords to be as strong as other cryptographic keys, so I'd recommend a minimum of 128 bits of entropy.
There are two easy methods, depending on how you want to encode the password as text (which really doesn't matter from a security standpoint).
For Base-64, use something like this:
SecureRandom rnd = new SecureRandom();
/* Byte array length is multiple of LCM(log2(64), 8) / 8 = 3. */
byte[] password = new byte[18];
rnd.nextBytes(password);
String encoded = Base64.encode(password);
The following doesn't require you to come up with a Base-64 encoder. The resulting encoding is not as compact (26 characters instead of 24) and the password doesn't have as much entropy. (But 130 bits is already a lot, comparable to a password of at least 30 characters chosen by a human.)
SecureRandom rnd = new SecureRandom();
/* Bit length is multiple of log2(32) = 5. */
String encoded = new BigInteger(130, rnd).toString(32);
Creating new SecureRandom objects is computationally expensive, so if you are going to generate passwords frequently, you may want to create one instance and keep it around.
A Better Approach
Embedding the password in the XML itself seems like a mistake.
First of all, it seems like you would want to authenticate a sender before processing any documents they send you. Suppose I hate your guts, and start sending you giant XML files to execute a denial of service attack. Do you want to have to parse the XML only to find out that I'm not a legitimate partner? Wouldn't it be better if the servlet just rejected requests from unauthenticated users up front?
Second, the passwords of your legitimate partners were protected during transmission by HTTPS, but now they are likely stored "in the clear" on your system somewhere. That's bad security.
A better approach would be to authenticate partners when they send you a document with credentials in the HTTP request headers. If you only allow HTTPS, you can take the password out of the document completely and put it into an HTTP "Basic" authentication header instead. It's secured by SSL during transmission, and not stored on your system in the clear (you only store a one-way hash for authentication purposes).
HTTP Basic authentication is simple, widely supported, and will be much easier for you and your partners to implement than SSL client certificates.
Protecting Document Content
If the content of the documents themselves is sensitive, they really should be encrypted by the sender, and stored by you in their encrypted form. The best way to do this is with public key cryptography, but that would be a subject for another question.
I'm unclear why transmitting the passwords over SSL -- via HTTPS -- is being considered "insecure" by your audit team. So when you ask for two things, it seems the second -- ensuring that the passwords are being transmitted in a secure way -- is already being handled just fine.
As for the first, we'd have to know what about the audit exposed your passwords as insecure...
I'd abandon the whole password approach and start using client certificates allowing a 2 side authenticated SSL connection.
You have to generate and sign individual certificates for each client. In the SSL handshake, you request the client's certificate and verify it. If it fails, the connection ends with a 401 status code.
Certificates can be revoked at any time be your side, allowing easily disconnecting former customers.
Since all this happens in the handshake prior to the communication, is is not possible to flood your server with data.