A client need to be authenticated by the server, so it need to send credentials. The credentials can be stored in a client database as in encrypted form. Since the server's certificate is known, in order to provide best security the client can use the public key of the server to encrypt the password. But the problem is now how to send the password without double encryption.
For example, suppose the server's authentication URL is "https://example.com/a?u=user&p=password", so the client have to send the SSL-encrypted data of this string to the server. Since the client stores only the encrypted password, it must find a way to send ssl_encrypt("https://example.com/a?u=user&p=")+pre_encrypted_password as a whole to the server.
The client is using WinHTTP api, so are there any way to achieve this?
No. SSL does not work that way - data sent over an SSL connection is encrypted using a symmetric cryptographic algorithm (usually AES, RC4, or similar), using a key that is established during the initial SSL handshake. The public/private key of the server are only used during the initial handshake; after that, they are not used.
Anyways, storing the password this way does not make it any more secure. If it's stored in an encrypted form that can be sent to the server, anyone who managed to get it would be able to use it that way; that encrypted form is password-equivalent, so it's no better than just storing the password!
Potentially you can save the certificate sent by the server (assuming that this certificate has RSA key which allows encryption), then use it in PKCS#7 encryption of your data, and send the encrypted data to the server. There's another question that appears - does the server-side code have access to the certificate. This is not the case in many configurations. So the server won't be able to decrypt the data.
Also, as pointed by EJP, this does not make much sense as you will be double-encrypting the data with merely the same key (technically keys will be different but the added security level will be minimal).
Related
I have a general question about the right handling of sensitive data.
Use case scenario
A user sends sensitive data (documents or images) via an API to a Node.js server. The server then stores the data on the IPFS.
Currently the server is used in order to encrypt and decrypt the data, so that the plain text isnt stored and available on the IPFS. For encryption I am using a combination of AES and RSA similar to this example.
Questions
Would encryption with AES alone be sufficient, since hybrid encryption of AES and RSA is not really used in this case?
Should I add an additional layer of security between the client and the server (hybrid encryption, session key ...) or is a standard HTTPS connection sufficient in this case?
Any other tips or best practices I should consider? (I am not an security expert)
EDIT
Requirements and important points
The application is supposed to create licenses for uploaded Content. For this reason, the uploaded content should be secure and accessible only to authorized persons.
A person is authorized to view content if a corresponding license is available (can be queried by the system).
User experience and simplicity is important aswell
So I think a proper balance of security and usability would be ideal. Complexity or financial costs don't matter at first.
In principle, a user should not have to possess a private key. Therefore, I thought that hybrid encryption might be appropriate if an HTTPS connection is not "secure enough". My understanding would be that the server has a private and public key. When the client connects, the server tells the client the public key. Then the client generates a key for symmetric encryption (e.g. AES) and encrypts it with the server's public key. In this way, the key can be decrypted by the server and both parties have the AES key. This key can then be used to send encrypted content to the server and decrypt it there. The decrypted content can then be re-encrypted and stored on the IPFS.
Thanks in advance.
I'm wondering how I can guarantee that messages received by the server are definitely from a client that is running my app on their smartphone.
Messages sent by clients running my app will be secured by SSL encryption, so would a good solution be to include some sort of secret key that is stored on the device and on the server, that is then embedded within the message body? (but then this key is prone to being discovered through reverse engineering)
Well, no, if you cannot trust your code and if you do not have access to some kind of protected key store (that performs it's own encryption, e.g. a TPM or suchlike) then anybody can steal the key. If you require authentication you can of course use the normal authentication methods such as user passwords.
If you require the messages to be protected you can then derive a key from the password (using a PBKDF such as PBKDF2 for instance), decrypt a private key with it and use it to sign the messages. If that's too slow, you can use the private key to encrypt a session key, and use a message authentication code.
We are currently designing a smartphone application that needs an authentication protocol.
We will use HTTPS for all the messages. The idea is the following :
The client contacts the server and authenticates himself with his user/password combination.
The servers replies with a ramdom-generated token that is stored in the database.
To contact the server the client now uses his/her user/token combination.
In each message he sends, the server has a certain probability to regenerate a new token that it includes in the message it sends.
The question is : will we have security issues using this protocol ?
Note : passwords and tokens are stored hashed in the database.
The security bases on the certificate you use for encryption. In general this is enough, you may also check if it is the expected certificate. In the case that you check yourself the fingerprint of the certificate you can be sure (if you use sha1 or better) that the certificate is from you and not a successful man in the middle attack. E.g. the NSA could simple create valid certificates for your domain, but AFIK it is impossible to generate a second certficate with the same fingerprint.
By the way I hope that the passwords and tokes are also salted. That is important so it is impossible to see that two customers uses the same password and also it increases the complexity of the hash, that means that it will take much more time to crack such a password with a rainbow table.
I'm trying to figure out the best way to secure an API. I only allow SSL and I'm using OAuth2 for authentication, but that doesn't seem like enough.
The major concern I have is that anyone could inspect the requests being made by a legitimate client to the API and steal the OAuth client_id. At that point they would be able to construct any request they want to impersonate the legitimate client.
Is there any way to prevent this? I've seen people use a HMAC hash of the parameters using a secret key known only to the client and server but I see 2 problems with that.
It's very difficult (impossible?) to prevent a malicious user from decompiling your client and figuring out the secret key.
Some parameters seem odd to make an HMAC hash of. For example if a parameter was bytes of a file, do you include the whole thing in your HMAC hash?
You can deploy mutually-authenticated SSL between your legitimate clients and your API. Generate a self-signed SSL client certificate and store that within your client. Configure your server to require client-side authentication and only accept the certificate(s) you've deployed to your clients. If someone/something attempting to connect does not have that client certificate, it will be unable to establish an SSL session and the connection will not be made. Assuming you control the legitimate clients and the servers, you don't need a CA-issued certificate here; just use self-signed certificates since you control both the client-side and server-side certificate trust.
Now, you do call out that it's really hard to prevent someone from reverse engineering your client and recovering your credential (the private key belonging to the client certificate, in this case). And you're right. You'll normally store that key (and the certificate) in a keystore of sometype (a KeyStore if you're using Android) and that keystore will be encrypted. That encryption is based on a password, so you'll either need to (1) store that password in your client somewhere, or (2) ask the user for the password when they start your client app. What you need to do depends on your usecase. If (2) is acceptable, then you've protected your credential against reverse engineering since it will be encrypted and the password will not be stored anywhere (but the user will need to type it in everytime). If you do (1), then someone will be able to reverse engineer your client, get the password, get the keystore, decrypt the private key and certificate, and create another client that will be able to connect to the server.
There is nothing you can do to prevent this; you can make reverse engineering your code harder (by obfuscation, etc) but you cannot make it impossible. You need to determine what the risk you are trying to mitigate with these approaches is and how much work is worth doing to mitigate it.
Are you running the OAuth authentication step over SSL itself? That prevents all kinds of snooping though it does mean you'll have to be careful to keep your OAuth server's certificate up to date. (Note, the OAuth server can have a public SSL identity; it's still impossible to forge with even vaguely-reasonable amounts of effort. It's only the private key that needs to be kept secret.)
That said, you need to be more careful about what you are protecting against. Why do people have to use your client code at all? Why does it have to be “secret”? Easier to give that away and put the smarts (including verification of login identity) on your server. If someone wants to write their own client, let them. If someone wants to wave their account in public in a silly way, charge them the costs they incur from their foolishness…
Our clients call our web service over SSL and authenticate themselves with a username and password. Our server then generates a symmetric key and sends it back to the client.
Then, the client establishes a TCP connection to our server, and sends a login message. At this point, I want to authenticate the client.
My idea is to have the client encrypt a well-known/static piece of text with the symmetric key and use this as proof that it is in possession of the key.
Since the symmetric key is generated randomly, is it ok that I use a static piece of text here?
Any input appreciated.
SSL is built to authenticate both client and server, and asymmetric cryptography the most secure primitive you can use in this scenario. Symmetric ciphers can be used for authentication by using a Cipher Block Chaining Message Authentication Code other wise known as CBC-MAC mode. The use of CBC-MAC has similar protection as an HMAC, but utilizing a symmetric cipher instead of a message digest function. CBC-MAC mode is used by WPA to protect wireless networks.
Your idea is subject to a replay attack - if someone observes a user logging in, they can store the static-text-encrypted-with-symmetric-key and use it later to authenticate themselves.
The accepted way of doing this is a challenge/response. The client connects, the server generates a random challenge and sends it to the client, and the client responds with the encrypted version of the challenge (although you should actually use a HMAC here, rather than a block cipher, because otherwise your client is effectively a one-block decryption oracle!). It would also be safer to use two different random keys (provided at the same time over the web service), one for encryption and one for authentication.
Note though that this scheme, as written, is still susceptible to a man-in-the-middle attack. You are definitely better off using SSL, as The Rook suggests. This will require your client to generate a public key and send it to the web service. The web service responds with a signed certificate containing the client's public key along with the client's unique identifier (username, or whatever) in the DN field. The server on the separate connection verifies the client certificate used (ensuring it's signed by your web service), and verifies that the client identifier in the certificate matches the client that is asking to connect.