I have an asp.net application, accessed by people over the internet using web browsers. It runs on a web server and it talks to a backend database.
Some of the users would like to use the application to store some private data. The requirements of this are:
1) Only the user who stored the data should be able to see it.
2) The developers/dbas should not be able to see the data.
3) If the web server and database server were compromised a hacker must not be able to decrypt the data.
So, it's obvious I'm going to have to encrypt this data. If I encrypt it there will be a key somewhere and probably a salt/IV. The question is where do I store the data which is used to perform the decryption? If I store it in the database or the web server then a developer, dba or hacker can access it and decrypt the data.
I think my ideal solution to this would be for the private key to be on the clients machine, that way they are entirely responsible for it. But I'm not sure of how to go about this with an asp.net web application.
I believe I can create a certificate which also stores a private key (PFX). The client companies could use group policy to deploy the certificate to their domain. But it is possible that the ASP.Net application can request the web browser to send the private key to it so that it can perform the decryption? Decrypting on the client would be best but other than creating something in javascript I don't see how this is possible.
Any advice welcome.
Store the key in the mind of the user. Use any password/passphrase based key derivation algorithm you like. The standard is PBKDF2. The optimum choice of algorithm will depend on precisely what your security requirements and threat mode is. Ideally, that decision and the implementation should at least be reviewed by a security expert.
Is it possible that you deploy a ClickOnce application as a part of your solution? The ClickOnce could easily access the cert store on a local machine thus allowing you to perform client-side encryption.
Related
Let's say I have a MySQL database into which users can enter some personal data like postal addresses via a php website. The users can NOT log into this site to later verify what they have entered. The enterprise they have entered their data for (voluntarily of course) then can use this data to maybe send the users actual mail (you know, postal services and such) or emails (of course the users agreed beforehand that they want to receive emails). The database serves merely as a store for the data and I want it to be a bit safe. If anyone breaks into the database, retrieving the email address and the actual first and last name (many email addresses contain both anyway) might not do much harm, but knowing where people live could be too much of a giveaway.
The enterprise is accessing the database via a C# front-end that targets stored procedures within the database to do stuff, including searching for users based on their email address.
From what I have gathered through searching I could think of the following procedure to handle the personal data in a more secure way (than saving them as plain text in the database)
before submitting the sensitive information to the stored procedures the plain text gets encrypted with a key while still in php, so all the MySQL server logs see is encrypted data
the front-end uses the same key to make the data humanly readable again when it is displayed to the enterprise's users (They need to access this private information and the user is comfortable with the enterprise doing so, that's the whole point of this scheme)
My line of thinking is: These are not passwords that are stored so I don't need all the password hashing trickery (As I understand it, when securely saving a password in a database, you use a one way algorithm, so you can never reverse engineer the password straight from the database but have to hash every password you want to try and test that against the desired database entry to see if you chose the right password) but can instead go for a simple encrypt/decrypt, because I don't want to brute force every address out of the database.
There are a few rough edges that raise concerns for me:
I need to somehow provide the key I want to encrypt by to php. Usually this is done via a library or external php document, like you provide the database connection information in a separate php file which resides in a folder on the server which is not accessible from the web (The server will say access denied if you try to access it) Is this a good practice and can I be sure that this key-file is really safe?
I need to provide the key to the front-end as well. This should be done separately in a (maybe encrypted?) config file for the front-end. Is it wise to have the key in two places, albeit for two different systems? The key must never change or else part of the data will be lost!
Somehow I have the feeling that if someone knows how to access the database he/she probably figured out where the connection data was and how that was to be accessed. Oh look, here is an encryption key, I wonder what that does. How likely is it that if the database access is breached the encryption key is in the open as well rendering all efforts to give a little extra of privacy to the users void?
If I wanted to add another bit of "extra security" and encrypted the email address as well I would have to encrypt every email address I want to search for from the php or the front-end, right?
Having searching procedures using ´RLIKE´ will break on encrypted fields, won't they? So to retain searching for parts of an email address I cannot encrypt the email entry, right?
I will have to change my database fields to binary to accommodate encrypted data or make them bigger and base64-encode them, won't I?
Is there an encryption/decryption algorithm ready to use in PHP 7.0.7 and C#? (I don't worry that much about C#) One that is reasonably secure while not bloating my tiny texts to massive chunks of binary? I don't know if that is of any consequence, but if I use for example a 256 bit key, that's 32 bytes. If the street part of the address is shorter that 32 characters, will the encryption work? Will there be cumbersome padding involved?
All in all I feel that the security gain is minute compared to the measures I have to take in my php files as well as in the code for the front-end. The perceived security gain might be bigger ("Woha! They are saving our data encrypted! They sure know what they are doing!"). Having strict and restrictive privileges for certain types of users (for example revoke ´SELECT´ commands) should in all be more helpful, shouldn't it?
Edit for #Luke Joshua Park:
Thank you for your detailed answer.
I suppose by API server you mean the webserver my php's reside on? This indeed should be separate from the database server. Both servers are hosted within a university's network but can be accessed from the internet.
I can follow the authentication path to the point where every user from within the enterprise (small-ish project at said university, maybe a bad choice of wording) has a database user with sensibly set grants. But users from outside using the php only send data to be stored in the database (ideally with a common but seperate database-user with grants set accordingly), and never retreive (their own) data. Using authentication would mean they first had to create an account (which is not needed) and how do they authenticate themselves for creating the unwanted account?
It is good that you're asking these questions before implementing a solution, cryptography is difficult to get right and a sound understanding is required before you start.
I'll answer your questions quickly first, but the more important part is what follows.
Not really. See below.
Yes, in most cases, keys should be kept on the device they are created on, wherever possible.
Provided your API server(s) doesn't also have the database on it, relatively unlikely.
Yes.
Yes.
Yes. But don't base64 them. Wasted space and processing power for no benefit.
You're asking the wrong questions. An algorithm isn't "for" a language. You just need to pick the right algorithm/block mode/padding depending on your needs.
For the most part the questions you are asking are irrelevant. Believe it or not, your issue is more to do with authentication than it is to do with encryption.
The first thing you need to understand is that a server breach is a server breach. Bad stuff is going to happen regardless of how much cryptography you throw at it. But we can minimize damage where possible.
Your database software should be running on a separate server/instance/whatever from your API server. Encryption/decryption should only take place on your API server. This has the benefit that both your API server and database server would have to be breached in order to decrypt the data (to access the keys). How you store the keys on your API server isn't all that important provided they aren't in your webroot or something silly like that.
Everything past this is authentication. You need a strong authentication system to determine who can send you information and who can retrieve information from you. Communication to and from your API server should obviously be encrypted with TLS at all times. You might consider TLS client authentication as a way to ensure the entity requesting data from you is who they say they are. Usually client authentication can't really be used on the web, but if you're interacting with "enterprises" in a more private way, then client authentication is an excellent choice.
In summary:
Separate your API server from your database server. Encryption keys should only ever be on the API server. See this repository for a collection of encryption examples from PHP to just about any other language.
Use TLS for all ingoing and outgoing communication.
Focus on authentication. TLS Client authentication is a good option.
I want to create an UWP app for a web API, which provides API keys for app developers.
Basically I would need to include some constant values with my app to generate some HMAC authentication tokens and pass them in the request header.
However, I'm not familiar with how UWP apps are delivered and deployed. Probably not very securely. I'm afraid if I did this, someone would simply decompile the app and steal the keys, like how regular .NET apps can be decompiled.
So what I would like to know is if I can deploy the app with secrets, and if not, how is this kind of problem solved usually with apps?
Also, if it is possible to deploy an app with secrets securely, how can I update those secrets if I would ever need to?
What you are looking for is the Microsoft Data Protection API (see https://msdn.microsoft.com/en-us/library/ms995355.aspx).
Basically the operating system provides you a service/api which securely allows you to store data. It uses the user authentication to encrypt and decrypt data. You may delete / write a key whenever you like.
I would suggest you calculate a key using ECDH (Elliptic Curive Diffie-Hellman) between your client and server (api) and then store the mutual agreement in the keystore. You decrypt your key on runtime, you might want to store the variable then in a SecureString. However keep in mind your api needs to keep track of the generated mutual agreements (also securely).
Here Microsoft explains on how to implement DPAPI:
https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection
Ok, I'm asking a rather generic question to a specific problem. I have searched this in more ways than I can count, and nothing seems to work. Let me explain my need and then I'll mention a few of the best solutions I've found and why they don't work in my case.
I have an application that a user launches and uses to set up various configuration values that are saved into an app.config file. This is a WPF application. Specifically, some of this data are HIGHLY sensitive.
This data needs to encrypted and subsequently decrypted by a Windows Service that will be launched by the application once the configuration step is finished. The general solution given for this scenario is to use DPAPI, which has two modes for encryption: User and Local Machine.
If you use User-level encryption, your application will encrypt and decrypt data as much as it desires, as long as the current user that initially encrypts the data is doing the decryption. My problem is that when the service is started, it also restarts on reboots and will specifically be running under a different user account.
The next approach, using DPAPI, is to encrypt the data as the Local Machine. This means that when ANYONE logs into the machine can decrypt the sensitive data. This is a BIG no-no!
What I need is to have a way for a user to specify the data he wants to encrypt and then specify an account (in this case, what will be the service account) and use it for data encryption.
I can't find how to do this. This MSDN article alludes that can be done. (See section 'Web Farm Scenarios'.) The TL;DR on that article is that for ASP.Net applications, you can use the RsaProtectedConfigurationProvider to encrypt your data, and export the keys to be used with a specific web account. This is close to what I want, but in my case I need to create the data in a WPF application and store it to be used in a Windows Server Service.
How can this be done?
You can accomplish something similar to this using something as mundane as EFS, but unlike raw DPAPI, a recovery key might bypass the protection. In either case, a local admin could replace your program with his own and it would have full access to the decrypted data.
As for setting this up, the easiest way to do that would be to interactively log on with the service account and either create the protected data using System.Security.Cryptography.ProtectedData or create a file in a directory marked with the "encrypt" attribute.
Use the account name as the salt for your encryption, decyption should use the logged in account name as the salt to decrypt.
i have a suggestion , you can create User group add required users into that group. And encrypt and decrypt data only if user is part of that group using second method.
If I have a stored key file used to decrypt the encrypted input coming into my application, and I store that key file as an embedded resource so that it is embedded in the assembly when deploying, how difficult would it be for someone to reverse engineer the application and retrieve the key file?
Also, the application is deployed through ClickOnce "Online only" mode which I imagine would also make it more difficult to reverse engineer? (I'm not exactly sure of the workings of ClickOnce but I wasn't able to find the dll's/assemblies on my local machine after running the application in online only mode...).
Update:
As Ralf essentially answered the main question below in his comment (answer: it's not really safe at all), here's some more information so that you knowledgeable people can possibly suggest a better security model.
The encryption will be used to encrypt the login password for my application, to be used in a SSO setup (the user will first sign on to a different system and then by clicking a link will be able to directly open my application without having to enter in their login details).
The encrypted data will be sent as a base-64 string URL parameter in the link that will launch the my click-once application.
I will also be developing the application that will create the encrypted data for the URL parameter (clarification: not the first application the user will sign in to for the SSO, I will only be creating a small tool to convert the plain text password into an encrypted base64 string).
It's only an internal application so bullet proof security isn't essential and ease of deployment is more important, but it'd be nice to know what the best practices and different options that are available.
Whether in clear text or encrypted, you don't want to store the password. When you get a password, all you should do is pass it to your server app where you compare it against the salted hash of the password you have in the DB. Even if you don't think security is that important, you need to take care with the password because people frequently reuse passwords across different systems. I know they shouldn't but they do.
If you want to implement a single sign on (SSO), create a sign on token on the server side and pass it back to the client, either encrypted or signed (HMAC is a good choice for signing). This is an unforgeable token because you need to know the encryption key or shared secret for the HMAC and that data is only known on your servers. So you have your SSO and all data involving the SSO is managed on servers so there's no data leakage or chance of spoofing.
As long as the aplication can be launched, the files have to be somewhere on the computer. You just have to know where to look. The reverse-engineering may be ugly but it is always possible. The computer has to be able to understand what he is supposed to do so you only have to extraxt the information one is looking for. Therefore the security of your application should never depend on the difficulty of reverse-engineering! I believe that a secure application should be open-source anyways.
You propably need a diffent security model. The important thing here is that you know against what you want to protect the data. If you simply want that you know the data is sent by the server and not somebody else (man in the middle attack) you could use digital signatures instead.
If you do not want anybody to read any data sent between server and client you should use some sort of ssl implementation to create an encrypted channel. Then you only need to watch out that the public key of the server is not altered on the client. This may be done by an certificate of an official CA but unfortunately those are usualy not for free.
I would like to use TDE, but I cannot use it, so I have chosen to use the EncryptByCert and DecryptByCert functions. However, I was also considering encrypting/decrypting data in c# as shown here.
My question is are EncryptByCert and DecryptByCert unsecure because the certificate is also stored in the database? How do people get around this problem?
Is using the c# built-in encryption a better idea?
Thanks in advance for any help. :)
There is an Encryption Hierarchy one has to deploy:
(source: microsoft.com)
The root key used can be the service master key (actually the root is the service password, but this is transparent to the service start), in which case the applications can access the data just by simply connecting to the database and decrypting it. This protects the data if the database file is lost accidentally, but does not protect the data against compromised access to the server: since the decryption key is held by the server itself (the service master key) then anyone that has access to the data can see the data, because anyone can decrypt it. The data is protected through normal access rights and permissions, but the cryptography does not add any protection against authorized users.
The other option is to rely on a password at the root o encryption hierarchy, in which case the application must ask the user for the password to access data. For instance, if is a web site , the user would have to fill in a data decryption password in order to access a specific page. This truly protects the data cryptographically against users that gain access to the data through ordinary data access permissions and don't know the password(s).
SQL Server 2008 also offers the possibility to leverage a hardware TPM to store the decryption key (ie. an employee badge) but this is Enterprise Edition functionality only.
Ultimately, asking if the SQL Cryptographic API is secure or insecure is a non-question. The API itself of course is secure. Encrypting with the data with a symmetric key and then encrypting the symmetric key with a certificate and storing the private key of the certificate along with the data in the database is secure, as long as the private key is properly protected. The security or insecurity of a cryptographic deployment it always ultimately driven by the key management (bare some faulty implementation, but lets assume the implementation is perfect) and key management is 1% application design and 99% human process.
Ultimately, you need to do a serious threat modeling (sorry, but "The threat is that the data is private information and should not be seen plain text." is not threat modeling). Follow a methodology like STRIDE, or other similar methodologies. This is a very hard domain, and is deceptively simple to read about cryptographic APIs and believe that you know how to protect data:
The world is full of bad security
systems designed by people who read
Applied Cryptography