My company is going to be storing sensitive data for our customers, and will be encrypting data using one of the managed .NET encryption algorithm classes. Most of the work is done, but we haven't figured out how/where to store the key. I've done some light searching and reading, and it seems like a hardware solution might be the most secure. Does anyone have any recommendations on a key storage solution or method?
Thanks for your replies, everyone.
spoulson, the issue is actually both the "scopes" that you mentioned. I suppose I should have been clearer.
The data itself, as well as the logic that encrypts it and decrypts it is abstracted away into an ASP.NET profile provider. This profile provider allows both encrypted profile properties as well as plain text ones. The encrypted property values are stored in exactly the same way the plain text ones are - with the obvious exception that they've been encrypted.
That said, the key will need to be able to be summoned for one of three reasons:
The authorized web application, running on an authorized server, needs to encrypt data.
Same as #1, but for decrypting the data.
Authorized members of our business team need to view the encrypted data.
The way I'm imagining it is that nobody would ever actually know the key - there would be a piece of software controlling the actual encrypting and decrypting of data. That said, the key still needs to come from somewhere.
Full disclosure - if you couldn't already tell, I've never done anything like this before, so if I'm completely off base in my perception of how this should work, by all means, let me know.
There only two real solutions for (the technical aspect of) this problem.
Assuming it's only the application itself that needs access the key...
Hardware Security Module (HSM) - usually pretty expensive, and not simple to implement. Can be dedicated appliance (e.g. nCipher) or specific token (e.g. Alladin eToken). And then you still have to define how to handle that hardware...
DPAPI (Windows Data Protection API). There are classes for this in System.Security.Cryptography (ProtectedMemory, ProtectedStorage, etc). This hands off key management to the OS - and it handles it well. Used in "USER_MODE", DPAPI will lock decryption of the key to the single user that encrypted it.
(Without getting too detailed, the user's password is part of the encryption/decryption scheme - and no, changing the password does not foul it up.)
ADDED: Best to use DPAPI for protecting your master key, and not encrypting your application's data directly. And don't forget to set strong ACLs on your encrypted key...
In response to #3 of this answer from the OP
One way for authorized members to be able to view the encrypted data, but without them actually knowing the key would be to use key escrow (rsa labs) (wikipedia)
In summary the key is broken up into seperate parts and given to 'trustees'. Due to the nature of private keys each segment is useless to by its self. Yet if data is needed to be decrypted then the 'trustees' can assemble thier segments into the whole key.
We have the same problem, and have been through the same process.
We need to have a process start up on one computer (client) which then logs in to a second computer (database server).
We currently believe that the best practice would be:
Operator manually starts the process on client PC.
Client PC prompts operator for his personal login credentials.
Operator enters his credentials.
Client PC uses these to login to the database server.
Client PC requests its own login credentials from database server.
Database server checks that operator's login credentials are authorised to get the client process' credentials and returns them to the client PC.
Client PC logs out of datbase server.
Client PC logs back into database server using its own credentials.
Effectively, the operator's login password is the key, but it isn't stored anywhere.
Microsoft Rights Management Server (RMS) has a similar problem. It just solves it by encrypting its configuration with a master password. ...A password on a password, if you will.
Your best bet is to physically secure the hardware the key is on. Also, don't ever write it to disk - find some way to prevent that section of memory from being paged to disk. When encrypting/decrypting the key needs to be loaded into memory, and with unsecure hardware there's always this venue of attack.
There are, like you said, hardware encryption devices but they don't scale - all encryption/decryption passes through the chip.
I think I misunderstood your question. What you're asking for is not in scope of how the application handles its key storage, but rather how your company will store it.
In that case, you have two obvious choices:
Physical: Write to USB drive, burn to CD, etc. Store in physically secure location. But you run into the recursive problem: where do you store the key to the vault? Typically, you delegate 2 or more people (or a team) to hold the keys.
Software: Cyber-Ark Private Ark is what my company uses to store its secret digital information. We store all our admin passwords, license keys, private keys, etc. It works by running a Windows "vault" server that is not joined to a domain, firewalls all ports except its own, and stores all its data encrypted on disk. Users access through a web interface that first authenticates the user, then securely communicates with the vault server via explorer-like interface. All changes and versions are logged. But, this also has the same recursive problem... a master admin access CD. This is stored in our physical vault with limited access.
Use a hard-coded key to encrypt the generated key before writing it out. Then you can write it anywhere.
Yes you can find the hard-coded key, but so long as you're assuming it's OK to store a symmetric key anywhere, it's not less secure.
Depending on your application you could use the Diffie-Hellman method for two parties to securely agree on a symmetric key.
After an initial, secure exchange, the key is agreed upon and the rest of the session (or a new session) can use this new symmetric key.
You can encrypt the symmetric key using another symmetric key that is derived from a password using something like PBKDF2.
Have the user present a password, generate a new key used to encrypt the data, generate another key using the password, then encrypt and store the data encryption key.
It isn't as secure as using a hardware token, but it might still be good enough and is pretty easy to use.
Related
I have logins for different platforms (say facebook credentials for example), that I want to securely store in a database. I want to be able to use the APIs to login to these platforms through the app (automatically).
Is there a safe way to store these logins without losing them (can't hash them).
Thanks
You don't want to know the safe way. You want to know the secure way. :)
Guess what, there isn't one. Imagine this. You want to store some sensitive data. You use encryption. Great. Now the data is secure. What do you do about the key? Let the user remember it? No, you wanted to automatically do stuff, so you need to have the key lying somewhere (not that the user can remember random >128 bits...). What do you do with the key then? Encrypt it? Well, you already done it once. You can obfuscate, hide, put access rights and so on. If you want stuff to happen automatically, there needs to be a key lying around somewhere.
Look at KeePass for example. Imaging you could have stuff as secure as KeePass is. This is as far as you can go.
It is probably too much risk for your app to store credentials for third parties. If I were your target user, I would certainly not trust a platform to store my credentials to facebook and others in a way that the platform itself might have access.
Let's assume you assessed and accepted this risk, and your users will trust you for some reason. One thing you need to acknowledge is that if your platform is compromised, all of the credentials stored will be compromised, but you can limit the impact of such a breach, and that's what you should do.
You should use a hardware security module. Now that's traditionally really expensive and complex, but you can now use a HSM as a cloud service. All major cloud platforms have CloudHSM solutions, and also higher level services based on the HSM itself.
The point in a HSM is that a stored key is never released. You generate a keypair in the HSM, and there is no way to extract the private key. For cryptographic operations (like encyprtion, decryption) you send data to the HSM and it does it for you, without you ever knowing the key. The point is that even if there is a compromise, the impact is limited, because attacker access is timebound, and also you can apply proper auditing and access control on the HSM itself.
But the HSM does not store website credentials, it stores keypairs. So you can use something like Amazon Secrets Manager (or you could build your own, but that's really tricky), which itself is based on AWS KMS, and encrypts your secrets with a key stored securely in the HSM.
So you would
create a KMS key, if you have large customers, then probably one KMS key per customer (or if corporations, they can probably provide their own KMS keys, see Bring Your Own Key, BYOK)
use secrets manager to store secrets, ideally encrypted with your customers specific key
run your app in say AWS with an IAM role that allow it to access the secrets in Secrets Manager
Note that a similar architecture can also be set up without AWS or any other cloud provider, but it's a lot more complex.
What this provides you is
auditability (who used which key/secret/credential, and when)
possibility to revoke access
timebound access to your credential store even for an attacker that did compromise your whole application
an option to let your users know if there was a compromise in which case they will need to change their credentials in downstream services
BYOK as described above
Note that this is a fairly complex thing tom implement and get right, and also costs non-negligible money to operate. You would need processes and technical controls to mitigate numerous other risks. This is just a brief introduction into what you could actually do to secure those secrets.
I have found all over the internet that HSM is the best place to store keys, but I am left with many unanswered questions.How does interaction takes place between server,HSM and database?. Is it like the server retrieves the keys from HSM to decrypt the data from database? If we could retrieve the keys from HSM why do we need a HSM in between? we can use a secure DB to store keys.I feel like I'm missing something.
Different HSMs work differently.
Some store the keys internally but there are storage limitations. Some encrypt the keys and the encrypted keys are stored on the server.
Some will handle data encryption/decryption so the key is never outside the HSM.
HSMs also have different levels of hardening from attacks over the com port, hardware access (tampering: removing screws, etc), vibration/shock, heat, etc. When an attack is noticed the key encryption keys are erased.
Some have admin access control requiring multiple people to be present, each using a smart card and enter a password. Additional physical security may be provided by physical access control.
I've read several Stack Overflow threads, I still can't decide what is the best option for my case. And the most secure one.
Here is the story. My webapp is to help users automatically get an overview of some of their data available in some third-party website. I need to store for each user some third-party credentials. Each night or so, my server will connect to the third-party services on the users' behalf and retrieve the required data.
Most of those third-party sites do not implement any API or OAuth mechanism, so I was thinking to do some web scraping.
I've read in many places that storing the credentials in the DB is not a good idea - especially because my app needs access to the password (so it has to be encrypted in such a way I can easily reuse it).
So, I have two options left:
Whenever I access (via webscraping) the third-party service, I store on the server the cookies issued by that service, for future reuse. I encrypt them and keep them encrypted in a DB, and decrypt them only when I need them. The problem is that the cookie can be denied or expired after a while, and so the automatic process wouldn't work any more.
I store the credentials in the environment variables. I will be on Node.js and Heroku. That's an idea I found in another SO thread. But I'm wondering about the security of this idea. Is it really safe? No one can access them but me? And what about if I reach many users. Like 1000 users, with 10 services. That's 10000 credentials to store in the env variables. That doesn't seem like a good idea.
I found two interesting questions on Stack Overflow but they don't fit 100% with my use case.
Security model: log in to third-party site with user's credentials (that gave me the idea in point 1)
Rails storing third party credentials.. Anyone know best practice? (gave me the idea in point 2).
I add another answer because maybe this one will do the trick for you.
You said the main goal of your website is to have an overview of third party applications. But what if instead of updating this overview every night, you update it when the user logs in ? It changes everything, because you could use the user's password (of your website) as master password to encrypt (using AES) all the others.
If you do that, the communications between your server and the clients have to be encrypted with SSL pinning, because an attacker could perform a MITM, get the master password and all the others stored in the DB... (Even if in practice it's very hard because you need to hack the client AND the server)
Storing a lot of data that changes and grows in environment variables will never be practical, no matter if it's secure or not so this is pretty much out of the question, unless if you have a small fixed number of users.
Not storing credentials in the database is a very good advice, but the cookies are credentials and even if you store them encrypted, your app needs to be able to encrypt it to use it. (This is unlike the situation with verifying passwords of your users when you don't need to ever encrypt them, you only need to see if the provided passwords hash to the same values that you have stored).
This is a hard problem because to make it work you need to have some form of credentials (whether those are passwords or cookies) stored and ready to be used unencrypted (even if they are stored encrypted, you need to store the keys to encrypt it as well).
Also, what you are trying to do can be illegal. Mayke sure that you follow the TOC of every service that you're using or otherwise you may face legal trouble.
Plan for the attacker gaining admin access to the server. Your site will be very attractive to attackers, kind of a one-stop-shop for user credentials so you will need very good security of the login credentials.
There are more than two options for storing the credentials:
Use an HSM for the storage or individual credential encryption keys.
Keep the credentials on another dedicated server with no Internet access, 2-factor authentication and limit admin personal. Rate limit the access to this server and add rate alarms. Access this server on a per user credential basis over a non-Internet connection. The credentials will only be available to the Internet connected server in memory as used, not at-rest in a file.
Storing users credentials in a reversible way looks like a terrible idea anyway. But if you really want to store them, I suggest you to use the environment variables solution. But you can improve it. To limit the amount of data you store and don't have 1000000 variables as you said, you can just store an AES encryption key, store all credentials in a DB encrypted with this key, and you just have to get this key (which is in memory) and decrypt the DB. But there is another problem with this solution. As I said, this is stored in RAM memory, so it's not persistent, imagine your server has to reboot for X or Y reason... You will lose the AES key and also the credentials of your users... Moreover, if the attacker performs a memory dump, he will have access to the AES key...
I think the better idea is to store the cookies (in an encrypted way) and when this one expires, you alert the user (by mail, phone, notifications, ...) and ask him to fill his credentials again. But it's not a perfect solution ! Indeed the cookies are a type of credentials and shouldn't be stored either...
In the book Programming Grails, Burt Beckwith gives some really good insights about how to develop Grails applications which follows OWASP Top 10 recommendations in chapter 9.
Punctually,I'm trying to implement the recommendation for Insecure Cryptographic Store. That reads as follows
Do not store passwords in config files, or even in files on the filesystem. Instead, create
a web page that you use to initialize the system where people trusted with passwords
enter the passwords (using SSL!) when the application starts up. Ideally, you shouldn’t
trust any one person with all of the information to start the system. For example, to use
JCE encryption, you will need to load a java.security.KeyStore , and this requires a
password, and you use this to create a javax.crypto.SecretKey , which also requires a
password. Use different passwords. If two people know the key store password and two
other people know the key password (it’s a good idea to have backup users in case
someone isn’t available), then no one person can decrypt the data or be coerced into
giving someone else access.
I want to secure the Amazon AWS[1] Access Credentials that will be used by the application in order to use the KMS[2] API call to secure encrypt and decrypt information.
I would like and example about how this can be achieved. My initial idea is to use a Service in the Singleton scope which holds the credentials and those credentials are setted by a Controller which is responsible of loading the KeyStore and the SecretKey used to decrypt a previusly encrypted and store AWS Access Credentials.
[1]http://en.wikipedia.org/wiki/Amazon_Web_Services
[2]http://aws.amazon.com/en/kms/
I have a Silverlight 3 app which connects to a server to perform various actions. My users log in using Forms Authentication but the actions they request are run on the server using the AppPool account so when they go in the audit logs they're recorded against the AppPool account. PCI DSS regulations now require that the user's own ID is in the audit logs which means the action must be taken using the user's creds. Now, I can save the user's creds when they log on and submit them with each request and the actions being taken by the server can use those creds. But the PCI regs say that if creds are saved they must be encrypted (to avoid someone taking a memory dump of the PC and getting the password).
The only way I can see of doing this is to get a public key from the server and encrypt the password with it, then submit the encrypted password and decrypt it on the server using the private key. But Silverlight doesn't have asymmetric cryptography.
I guess I'm too close to the problem and there must be another solution but I can't see what it is. Can anyone help?
CLARIFICATIONS
It's an internal application. Up until now, I've been using IIS Forms AuthN over SSL to Active Directory - I'm not worried about protecting the password in transit, just whilst it's held in memory on the client. As I understand it, because I'm using Forms Authentication, impersonation is not possible on the server unless I use LogonUser, which means I need the password on the server, so I need to transmit it each time, so I need to hold it in the client, in memory, until the app closes.
Are you saying you need to store the password for re-use in the silverlight app? If you are concerned about the password appearing in memory un-encrypted then Silverlight then I think you're in trouble.
The .NET framework does have a SecureString class for exact purpose you outline.
Unfortunately the Silverlight version of the framework does not have this class. Hence even if you were to keep the logical storage of the password encrypted at some point your code would need to decrypt it before using it. At the point there is memory allocated containing the string in unencrypted form.
I don't know much about Forms authentication but if you can map the User principle to a domain user (which you seem to indicate you need) then you will want to use impersonation when running your code on the server.
Alternatively stop using Forms authentication and use Windows integrated authentication where you definitely can use impersonation server-side.
Encryption should never be used for passwords. When you encrypt something then it follows there should be a way to decrypt it. One way hashes should always be used for passwords. md5 and sha1 have been proven to be far too weak for any secuirty system.
Sha256 should be used, and in silverlight this library will take care of it:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256%28VS.95%29.aspx
In fact storing passwords using "encryption" is recognized by the vulnerability family CWE-257. The use of a message digest is the ONLY way to safely store passwords. I didn't just make this up, this is coming from NIST. There are many other vulnerabilities that come up when storing passwords. Here is THE LIST that NIST has put together: