3

I need to be able to communicate with a REST API Service and store the username/password pair in a database.

The client talks to the API from a server within our DMZ, but gets the credentials from a database outside of the DMZ within the network. I would like to be able to make this more secure so that if the server was compromised it would be difficult to access the credentials.

What is the best approach for storing the credentials securely? I can't use a salt & hashing mechanism because the API demands the username/password pair as plain-text and they control the authentication process.

Platform and languages in use: Windows/.NET/C#

4
  • Are the credentials stored on the Client machine, or separately? Is the Client machine and it's database operated physically like a PC, or is it something else i.e. a browser-based service? Commented Sep 6, 2016 at 14:40
  • 1
    "outside of the DMZ within the network" It's easy to get lost with descriptions like this. Maybe a more carefully and clarified distinction (i.e. how many computers are involved) would help? Commented Sep 6, 2016 at 14:41
  • It would also be helpful to know where you can influence the code, and the nature of the clients. I suspect that a viable solution would be to store the credentials encrypted in a form which could be decrypted by the client, or by the intermediate server using data supplied by the client.
    – symcbean
    Commented Nov 5, 2016 at 23:46
  • Look at Windows Credential Management API which can simplify storage and retrieval of user id/password.
    – jhash
    Commented Jan 5, 2017 at 15:14

3 Answers 3

1

The best option is to secure the REST service with a client certificate (instead of the basic auth credentials), if that is an option. This is usually achievable without changing the service's code-- it can typically all be done via configuration of the web server platform.

If this is not possible, you could still guard the basic auth credentials with the same security that secures your certificate store, like this:

  1. Generate a certificate for yourself, and import it (including the private key) into the an appropriate certificate store on the server-- probably a cert store that is private to the web server process. You didn't mention what platform you are on. If you're on Windows, you can put the cert in the user store for the app domain service account.

  2. Encrypt the basic auth credentials using the public key of the certificate. Store the encrypted credentials in your database, configuration file, or whatever your REST client uses.

  3. When you need to call the REST service, retrieve the certificate private key from the cert store, and use the private key to decrypt the credentials.

In theory this is sort of security by obscurity, but it has the benefit of leveraging all of the system hardening that is done around cert stores, which are obviously very sensitive. Now, maybe a hacker will be able to get into that cert store, but if he succeeds at that then you probably have much bigger problems.

This here article seems to contain all the details you'd need.

3
  • This seems the best answer so far IMO. Effectively once the server is compromised they have access to the database connection strings anyway. Obscurity is the key, do not show anything that is sensitive. How do I encrypt the basic auth credential using the key of the cert?
    – user183872
    Commented Dec 6, 2016 at 7:34
  • Please edit your question to include platform and programming language, and if they are in my skillset I'll try to answer.
    – John Wu
    Commented Dec 6, 2016 at 7:41
  • Please see my update.
    – user183872
    Commented Dec 6, 2016 at 11:18
1

One Solution

Addressing only the issue surrounding securely storing credentials. There is always a risk as the decryption key will still have to be stored somewhere.

For example, you could use OpenSSL to encrypt a string of text and then have that stored in the database on the "Insecure" Server. You'd have to use a reversible encryption method for this also.

Such a task could be accomplished with a simple PHP Script:

openssl_encrypt(PLAINTEXT, ENCRYPTION_METHOD, KEY, OPENSSL_OPTIONS, INITIALIZATION_VECTOR)

So in context, for example. (Ensure that you also add 16 bytes of padding before encryption and remove 16 bytes of padding on decryption, this can be removed by specifying specific OpenSSL options, however for ease, you can just add and remove the padding. Plus, this can also act as a degree of obfuscation, to a certain extent, in this example, 16 '=' characters have been used. This can also depend hugely on how your OpenSSL installation is configured, however, from personal experience, I always do just to be safe. Call it a touch of 'salt' if you would..)

openssl_encrypt("================username:password", "aes-128-cbc", "StRoNGeNcrYptIOnKey", 0, "16ByteIV--Random")

Running the above would produce something similar to:

+VUYZEh3FII7HRvJ8Qm8glERsgfsSKG9tE8Zyr2EJLL+9VaF7+41q/MeL8R1++L1

You can then run the subsequent decryption:

openssl_decrypt("+VUYZEh3FII7HRvJ8Qm8glERsgfsSKG9tE8Zyr2EJLL+9VaF7+41q/MeL8R1++L1", "aes-128-cbc", "StRoNGeNcrYptIOnKey", 0, "16ByteIV--Random");

Producing:

================username:password

There are a vast array of Encryption Algorithms that can be used. There is also a article on PHP.net showing how this can be achieved, and also includes Linux CLI examples, should you wish to do this via bash scripts also.

BEAR IN MIND

You will still have to keep a plaintext copy of the encryption key on your device if this is an automated process, which may not be ideal, nor would it be recommended. There is nothing to stop you using this approach and storing the encrypted data on your external server, however just take a moment to weigh up the security implications of storing a password in plaintext on a server.

If you're feeling neurotic

You could even encrypt the credentials once with one algorithm and then re-encrypt the cipher text with another, completely different algorithm.

Up to you, depends how secure the data is, and how much CPU time/justification/etc you want to dedicate to this.

Short Story

You need a reversible encryption solution if you want to be able to recover plaintext from cipher text and vice-versa.

2
  • Is the RijndaelManaged AES algorithm an alternative to encrypt the bytes? How does it stand against OpenSSL?
    – user183872
    Commented Oct 12, 2016 at 9:51
  • @user183872 RijndaelManaged in its default configuration is AES, and so is fine, as long as it is used correctly.
    – Xander
    Commented Dec 5, 2016 at 16:57
1

I think the task is very hard. Your server has access to the credentials. This means the process running has all privileges it needs to

  1. retrieve the relevant data from a DB (whether encrypted or not)
  2. access relevant items to decrypt (e.g. a key in the file system that is used for encryption/decryption)

If your server is compromised this means to me that someone injects code into the server and gets a shell at least as the user running the process (like www-data for apache). (If it is worse than that then it is game over anyway.)

This means that the attacker has the possibility to access the DB and most probably also access the encryption key.

That said, I can imagine 2 ways to harden the system.

Encryption key owned by root. You could write a server that is started as root, then forks its worker process children which actually do the work. First thing each child does is a switch user to www-data. Apache works this way. The encryption key is in the file system in a file with permissions 0400 (read access only for root). The dispatcher reads the key right after startup. After the children are forked it hands over the encryption key to the children over some interprocess communication method. If one of the child processes is compromised, the process running as www-data cannot access the key in the file system (only root can). The attacker would have to find a way to inspect the process memory to find the key. Not impossible but definitely nothing for beginners.

Separate storage and encryption. Let's assume your clients need to authenticate to the server (should be like that anyway). Then you can separate the tasks of storage and encryption. One service reads the encrypted password and sends it back to the client. A second service, which may run on the same box but as a different user does the decryption. So the client needs to perform 2 calls. What happens if one of the services is compromised? Then you can either decrypt an encrypted password xor access the encrypted records in the DB. The crucial point here is that you need to make sure that let's say the first compromised service cannot submit the encrypted password to the second service. But that shouldn't be possible if the client authenticates (and none of these 2 servers should know the cleartext credentials).

Looking forward to the community's comments.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .