I have a scenario that has been troubling me for years. If you have to connect to a database or other service (like a web service) using a username and password, where would be the safest place to store this information if you are connecting through a .NET assembly? I understand that you would have to encrypt the password, but then you run into a kind of chicken-egg problem -- fine -- you can encrypt it, but then where do you put the key?
In .NET, you can't hard-code the password because you can decompile .NET code.
I looked at using assembly based rights with Isolated Storage, but MS recommends against storing unencrypted secret items there because privileged users can gain access, so again, we are moving the problem from point A to point B. So, for example, a domain admin with no need to know about the information in a database would be able to get access because of the ability to be an admin on any workstation on the domain.
You can encrypt the App. Config and Web.Config, but I believe privileged users can access the keys.
I think you run into the same problem with DPAPI.
I had considered storing the passwords, encrypted in a remote database, and getting them through OS authentication, but our department prohibits the storage of passwords on database servers. I am pretty sure I am stuck and wanted confirmation.
ASP.NET Core Identity and password hashingThe app will create a hash of the password, and store it in the database along with the user's details. A hash is a one way function, so given the password you can work out the hash, but given the hash you can't get the original password back.
Hashing and encryption both provide ways to keep sensitive data safe. However, in almost all circumstances, passwords should be hashed, NOT encrypted. Hashing is a one-way function (i.e., it is impossible to "decrypt" a hash and obtain the original plaintext value). Hashing is appropriate for password validation.
The Security Account Manager (SAM) is a database file in Windows XP, Windows Vista, Windows 7, 8.1, 10 and 11 that stores users' passwords. It can be used to authenticate local and remote users. Beginning with Windows 2000 SP4, Active Directory authenticates remote users.
You don't want to store the password in the assembly, and reinventing the wheel only creates more trouble (and introduces more vulnerabilities) than it's worth. If you are using MS platform on both the database and web server, then the easiest way to handle this is use a trusted connection, and grant rights on the SQL server to the identity your application is using.
Second to that, I would just let DPAPI do its job to encrypt your connection settings.
****UPDATED for Windows 10 1903+ ****
Microsoft has removed the dlls used by the previous method from WinMetadata and they are now not available even when doing the old manipulations. Instead, they now either propose to use a Target Framework Moniker or a Nuget package called Microsoft.Windows.SDK.Contracts that expose the modern windows APIs. [The official detail could be found here].
Note that for the nuget to install correctly, it is essential that the packet management is set to PackageReference
instead of Packages.config
elsewise, even though it could look like it is installed, it won't work.
If it is not already set to this manager, it is normally possible to convert the packages.config file to the new format (that is integrated in the project file) by right-clicking the packages.config file and choosing Migrate
.
If the Packages.config file does not yet exist, it is possible to set the default to use PackageReference by going in the Nuget Options. Note that the default setting varies between .Net FW, .Net Std and .Net Core.
When I personally had to do it, weirdly, it didn't want to migrate the file. I had to completely uninstall my packages, delete the file, set the default and reinstall the packages. Something to do with TFVC if I remember well.
The APIs should then be available again.
**** ORIGINAL POST ****
If you are in a Windows only 8+ solution, you could also use the Windows Password Vault. Originally, this was built for Metro Apps but is also supported for Winform and WPF applications.
Basically, what you need is
Add the following line in your project file inside the first property group<TargetPlatformVersion>8.0</TargetPlatformVersion>
Reference Windows.Security
.
Windows
tabCore
sub tabWindows.Security
.In the code, use (this is vb but C# is equivalent)
Dim vault = New Windows.Security.Credentials.PasswordVault()
vault.Add(New Windows.Security.Credentials.PasswordCredential(resource, userName, password))
Dim cred = vault.Retrieve(resource, logon)
cred.RetrievePassword()
Dim pwd = cred.Password
Ref:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With