How to save SQL server password - c#

We have an application running multiple services and executables. Some one them need to access the SQL database, so I need to store the SQL server password somewhere. To avoid direct access to the password, the password is stored encrypted. To decrypt the string, a crypto DLL can be called, returning the plaintext password. Whats bothering me is, how to avoid that anyone can decrypt the password. The following options had been discussed and discarded, because they do not solve the problem of more or less direct access to the plaintext password:
The crypto dll contains all required information to decrypt the password: any malicous user may call the DLL to decrypt the password with his own component
Using DPAPI, I need to set the scope to LocalMachine, meaning any user logging on to the local system may decrypt the password.
2a. Using DPAPI and a service component running with special account would solve the "any local user can use the Unprotect method of DPAPI to decrypt the password" problem, however, the malicous user still can call the crypto service with his own component.
The crypto DLL requests a password, and encrypts/decrypts using a RijndaelManaged instance. Every calling DLL must know the password, meaning I just moved the problem to another component.
Integrated Security is not an option, customer's security policies deny to use IS
Any pointer how to solve this?

If it's a publicly available application, then you would be best to avoid storing any SQL connection string details in the winform app itself.
Instead, host a web service that the winform will communicate via.
This will ensure a malicious user cannot get your SQL connection details (at least, not from the winform app or associated dlls) and allows you to hide your SQL server away from the net.
There are many ways to secure a web service so that it can only be accessed by "approved" clients. (User authentication tokens, etc )

This will depend how far you think a user in the system will go to get at the connection string.
Do they need domain access to use your application?
Can you restrict IP addresses into your SQL server?
Do users have admin rights on their machines?
e.t.c.
Things like the above will narrow down the potential users that can gain access.
Some other things that seem to stand out are:
Move the KEY and IV outside the DLL as that seems to be the single point of failure if its stolen
Obfuscate the key and iv in your application code or store in certificates, possibly with DPAPI
Lock down access to your program files, make the application run under a restricted user.
Some other tips are here:
handling key and iv values
storing key in certicates
restrict SQL access by IP address

you could set the crypto dll's current public interface to internal only.
Then, using the InternalsVisibleTo attribute, you can specify one or more specific assemblies that can actually see those internal interface methods.
This will allow you to restrict access to your crypto library.
reference here: InternalsVisibleToAttribute Class
EDIT 1
The only downside to this would be if the malicious user was to decompile your crypto dll.
Whilst you can make this difficult to achieve, you can't avoid it altogether in .Net.
Also, you don't make mention of what level of risk (internal/corporate app, publicly available app, etc), which makes providing the best answer quite difficult.
(I say best answer, as there's no guarantee to any cryptography :))

Related

"Safely" store (on client side) tokens for reuse?

I'm trying to create a desktop application that will send updates to a web-service I am developing.
Ideally, the application would be configured only once and deployed to a network share. When configuring the application, the user will enter a password that is used to authenticate within the web-service. After that, a token will be created to be used on future connections.
This would allow any computer with access to the network share (even if it is not the computer in which the app was configured) to just run the application (which will connect to the web-service) without entering any credentials (because the token has been saved).
Question is: How should I protect this token?
I know that storing it client-side will never be completely secure, but I want to make it as hard as possible for someone to gain access to the plaintext token.
I'm looking for an answer that, preferably, does not depend on any operational-system resource (since the application can be executed from different devices).
Assume I have full control over the application and the web-server
I'm developing the console application using C#, but I believe this to be more of a theoretical question (not tied to any specific language)
Here are a few things I've tried/thought about:
Serializing the token using something like C#'s SecureString and storing it on a file: it's the best I've come with. But obviously, very trivial to reverse if someone gains access to the key file.
This answer suggests to use the Windows Data Protection API (DPAPI) (in C#, the ProtectedData class), but apparently, this would allow only the user who initially saved the credentials to access them, which would not work because I have to access the protected data from multiple users/devices.
Pass the token as a parameter to the application: this just changes where I'm going to store the token (on a batch file or OS task that calls the program, for example), but I don't think it makes it any more secure.
Since the user is not an administrator of the machine (this is a fundamental hypothesis), there are many ways to hide things from her.
What I propose is:
Make sure the main app runs under different credentials than the
logged user, a "special user".
Write another end-user app, just for setup, that talks to this app (using any interprocess communication you see fit, TCPIP, whatever, maybe secure but I wouldn't care too much at this). This app is used only to gather credentials and send them to the first app
Now, the main app can write the token anywhere the logged user has no access, but I recommand protected data because it's very easy to use
Here is some graphical explanation:
Since data encrypted using protected data (Windows Data Protection) can only be decrypted by the Windows user who has encrypted it, the logged on user will not be able to read the "special user" data.
I would suggest using JWT.
Your server would generate a Token after a successful authentication. The token would be sent to the client. Each subsequent call to the server would send the token in the header to the server. The server would then verify the token. If verified, the server knows the client has been authenticated.
No need to store usernames/passwords on the client.
There is no bullet-proof way to solve this problem, the client finally needs access to the server, and so can do an attacker with enough privileges on the client.
What you describe is a typical scenario for the OAuth2 protocol, since you have control over the server. With OAuth2 you cannot avoid the need to store a secret on the client, but by exchanging it for a token, you can protect the original password and you can guarantee that the token is very strong (user passwords tends to be weak).
To store the token/password on the client one could encrypt it before storage, but this immediately raises the question of where to store the key for this encryption. An attacker could extract it from the client. There are some ways, which can improve security for the key storage.
Depending on your situation you may consider the usage of a Hardware security module (HSM).
You can use an OS specific key-store like you mentioned with the data-protection-api. A key-store can only help protecting a key, because it has the support of the operating system (I think this is what you meant with SO-independend?). With the DPAPI you can not only restrict access to the logged in user, rather you can restrict it to the local machine. Key-stores are available on other operating systems as well.
Instead of storing the password on the client, it can be requested from the user each time the client starts. This can be reduced to the startup of the device, the password can then be hold exclusively in the memory.
Well, you can't protect anything in client side. Once it's there, anyone with privileged access can see it.
What you can do is make this piece of information useless without something else.
The best approach here would be to store a kind of public key in the client side and use this public key to create a hash to authenticate the user via webservice.
When the user configure the application, the server send this public key that the application stores locally. When the application call the server it will create a hash using this public key and a private key that is only known by the application and the server. Then the server can check if the hash is correct using its private key.
To improve security, you can use a timestamp in the hashing too, so it will change overtime and prevent the reuse of keys. Or it could send a new public key with the each webservice answer.
I would suggest you to use IdentityServer4 as it provides RFC compliant protocols and depending on the GrantType a client application is given in your context your desktop application.
Even though the token is in plaintext it is protected in the webservice where the Access Control(Issuer of token) validates that a token is being received from the correct client by checking the Origin in the clients request and the one stored in the database.

How to encrypt and decrypt sensitive information in C# without a user-entered password

Forgive me if this is a stupid and obvious question, but I'm having trouble googling for the correct resources. I'm not a security expert and I'm struggling to understand how to properly go about this.
Here's the scenario. I have an internal application on an internal server: not something that will ever go out to a client site. This application has a database of username and password pairs that are used to talk to secure web services. I have no need to keep these passwords secret from colleagues, but I want to protect them in case the server is attacked and the data stolen.
Traditionally one would salt and hash them. This is a process I understand in principle but it depends on the user entering a password which can then be validated against the stored hash. That's not the case for me.
So: searching around there are various solutions that use a fixed "pass phrase" to secure a string. Here's a one example, https://stackoverflow.com/a/10177020/271907 and here is another https://stackoverflow.com/a/10366194/188474.
However, as I understand it neither of these offers a useful solution in my case. That "pass phrase" is going to have to be stored somewhere for my application to do its work. If I hard-code it into the application it can be reverse engineered. If I encrypt it and put it in a separate file it can be stolen and worked out using a rainbow table.
I looked into using reg_iis to encrypt a key as per Encrypting Web Config using ASPNET_REGIIS but, to be honest, that just left me even more confused. I'm not even sure whether or not these encrypted config files can be ported between machines or whether I'd have to re-encrypt between dev and test and live. I don't know how secure they are either: AFAIK there has to be a key somewhere and if there's a key it can be broken.
To further muddy the waters I found this answer which doesn't use a key: https://stackoverflow.com/a/10176980/271907. However the author admits it's out of date and I have no idea how secure the result is.
Is there any kind of sensible approach to solving this problem that doesn't leave a hole in the security somewhere?
Any solution where you decrypt the password to check it is going to fundamentally be insecure because your application must always know how to do that decryption.
You can make it harder by not storing the decryption key in the code, but wherever you put it a hacker that can compromise your code can probably access anything it can access too.
Even if your application security is rock solid; your passwords are still plain text in your DB and if that gets compromised then lots of your users are exposed.
That said - this is an internal-only, low risk system. Your best course of action may be to let your bosses know the relative risk vs the cost of proper security and let them make an explicit business call (and carry any future blame).
The only way of doing this without leaving a hole in the security is by hashing and salting the passwords with a one-way algorithm. The fact that current passwords are plain text shouldn't be a problem - there are lots of ways to push users to encrypt them, but easiest is just to do it for them: next time they log in, if they have a plain text password encrypt it. Then after a suitable wait (depending how often your users log in) remove the old password and check against the new hash.
The golden rule is: if you store passwords you must hash them in a way you can't reverse
The only other option is for you to not authenticate at all - use NTLM or AD or OAuth to get some other service to authenticate the user and just trust that source instead.
If instead you're looking to secure the credentials the application uses itself then you have a similar problem, but the focus shifts. You still can't do much to avoid exposure if the host machine is compromised, but most attacks will only target files.
This can be a problem if all your connection details are held in a web.config or appsettings.json as compromising those files can expose your SQL server or other service passwords.
This is where you can use ASPNET_REGIIS - it lets you add secret configuration that IIS can access, but that isn't held in plain text with the web files.
In .NET core there's new Microsoft.Extensions.SecretManager.Tools that do the same thing.
Both of these add a layer of protection for any application credentials that would otherwise be stored in plain text on disk. Attackers must compromise the machine to get at them, rather than just the files.
In both cases these configuration details are no longer portable - you'll have to set them up again (and re-encrypt) on each server.
However, you only really need the additional protection in live - in development or testing sandboxes you can just use the plain text config, and then override the details with the encrypted settings on the live server.

Hiding MySQL credentials in a C# app

I am extending an open-source VoIP softphone application (written in C#/.NET) to my needs but don't know how to best approach this issue. I want the application to connect to database when a user enters his email address to log in, and perform a SQL query to fetch his account number using that email and authenticate with account number. But, I think including my MySQL connection credentials (host, username, database) is insecure? How should I do it?
It is indeed insecure.
You need software running on the server, that can accept said email and password as input and connect to your database (so the connection string is sitting on a machine in your control), check it and return either ACCEPTED or DENIED to the client. In your case, ACCEPTED could be just the account number you mention.
Bonus points if the email and password are transmitted from client to server app over an encrypted link (public key).
You should put the connection strings into a configuration file and then encrypt that portion of the file. There's a tutorial on how to do that here: Protecting Connection Strings and Other Configuration Information. Although the tutorial is for ASP.NET, the same principle will apply to pretty much any .NET config file.
There's also a similar question here: Encrypting passwords in WinForms app.config, .NET.
Our rule of thumb when designing database applications is to always use delegation and isolation.
What isolation means is that we isolate database interaction from the end user application through the use of services (i.e. web services, wcf, .net remoting, etc). In this way, the database is never directly exposed to the user.
What delegation means is that the database access is always performed on behalf of the end user by a well-known, limited-access database user (generally the user that the service is running as). If at all possible, the database access should be performed by a user authenticated by the network rather than by storing user names and passwords in connection strings or other semi-secure locations.
Finally, one important note: you should always encrypt your end-user's login and password information before sending it over the wire. This is a little extra work, but well worth it from a security perspective.
Can MySQL do Windows based authentication (i.e. on a domain)? If so, you could use that. Otherwise you might want to have credentials to a service, or use encryption, but you would need to include the encryption key so anyone dedicated to discovering it would.
You could code your connection strings so that they end up in your assembly and use a code obfuscator to protect it from disassemblers
There are many ways to do it, including obfuscation and other ways making it difficult to use outside of the application, but not impossible to retrieve/use.
How should you do it? The best way (as far as I know) is to give the account the minimum credentials necessary so that if someone does have the username and password he/she cannot do anything malicious with it. Permissions can be set up in many ways for user-specific data, such as views so a user can only access the correct rows. Basically, if security is a top concern, assign permissions conservatively and if necessary give different users different credentials.
You should host a (php/jsp/asp) script at your server with which your application will talk. you should not store your credentials inside the app at any cost.
Tthere are so many ways to just take out the information. Especially .NET applications. it doesn't takes more that 30 mins :p

Storing and encrypting SMTP credentials in the registry

I have a username and a password for an smtp server. Currently they are hardcoded in my code:
string userName = "username";
string password = "password";
Currently, anyone who disassembles my dll could see these strings, correct?
I wish to store these securely in the registry, in case of future changes to the smtp server, and/or the credentials. I am not worried about the smtp server address string's security. I am only worried about the credentials' security.
How do I do this without hard-coding the credentials anywhere? I wish to see encrpyted strings in the registry.
I can encrpyt the password, then store the encryption in the registry, delete the password from the code, and use the decrypted password assuming that it is correct. However, wouldn't someone who disassembles my code still be able to decrypt the encrypted string stored in the registry?
What is the safest way?
At some point, no matter how many layers of security you have, the code will have to use the unencrypted password. That means that someone with enough access to your system to view and/or modify the registry probably has plenty of access to your code to get your password no matter what you do.
I know as developers we tend to work with paranoia = Paranoia.Maximum; a lot, but sometimes you have to back it down some.
That said, there are some things you can do. If the credentials need to be that secure, consider storing them, if possible, in a remote database. You can store them encrypted on a remote server so that anyone having access to your machine won't necessarilly have access to the DB Server.
If you really want to turn the paranoia up, and make security the user's responsibility at the same time, have them provide a "secure location" for a file that contains the data. You can then recommend that the location be something like a thumb-drive which would be removed physically from the computer when your program is not in use.
In any case, with security, you want to think in terms of layers. No one thing you do will be sufficient for really good security, but by layering several measures you can increase security to the point it should be sufficient for your needs.
The problem is not new. Operation system starting with Windows XP hat credential API which can be used in different scenarios. For example CredRead (see also http://www.pinvoke.net/default.aspx/advapi32/CredRead.html) and CredWrite can be used to save in encrypted form any general credential information. In the corresponding fields of CREDENTIAL structure you can define for exaple the level of persistence the saved credentials (logon session, all subsequent logon sessions on this same computer or to other logon sessions of this same user on this same computer and to logon sessions for this user on other computers).
If you want that your application only read the credential information you can use CredWrite in a separate configuration utility used by administrators or use the API as a part of setup of your application.

Encryption to protect files from changes

I've been reading a little about encryption recently and am interested in protecting a licence file from tampering. Now this may not be the best way to do it, in which case I'm open to suggestions. But one way I was thinking of protecting it is to simply encrypt it.
However if I were to use encryption I'd need to use symmetric key, but this raises the question. If I store a key in the source code, with such tools as reflector, is it really worth it? It seems a fairly trivial task to obtain the initalization vector, salt, key etc and therefore break the encryption. Is there a way to protect a key in source? Or is this the completely wrong approach?
If you want to prevent tampering, you want signing/hashing, not encryption. Similar theory - but it means you can validate the file with the public key in the app, without requiring the private key that you keep on your server (and use to issue licenses).
Search for cryptographic hashing / signing.
Anything on the client side of the system can be compromised.
If you encrypt your file you must also somehow place the decryption key in your program. Anyone with a hex editor will be able to step through your code to find this key and then decrypt your license file and also create keys for your system.
Internet activation would be a good way to go, but I would see if you can find third parties to do this for you as they will have been down these roads before.
That said running your license file through some AES 256 encryption can't hurt :).
if you are speaking about MS/.NET environment, i recommend you the DPAPI.
It is an API used to store your data protected by a password. Then you can ask me "but then i have the same problem", the answer is no, because in this scenario you use a user password to protect your data. So what you have to do, to access your data, is run your application under a certain credentials. In MS environment, its the the best solution.
from the documentation:
DPAPI is focused on providing data protection for users. Since it requires a password to provide protection, the logical step is for DPAPI to use a user's logon password, which it does, in a way. DPAPI actually uses the user's logon credential. In a typical system, in which the user logs on with a password, the logon credential is simply a hash of the user's password. In a system in which the user logs on with a smart card, however, the credential would be different. To keep matters simple, we'll use the terms user password, logon password, or just password to refer to this credential.
What you're attempting is DRM; there is no 100% way to do this on current PC hardware. There are many measures you can take to obfuscate parts of your program. It's a tradeoff between how much you want to obfuscate and how many hurdles you want to make your paying customers go through.

Categories

Resources