I guess we all can agree, that storing Credentials in Code is a really, really bad idea! Not only can you reverse engineer the assemblies, but with Azure DevOps (or GitHub, ...) you can read the credentials in the clear.
Obfuscation does not help either, so if I ever see something like
private static string _password = @"klksndfl";
I think I'll cry!
But the question stands, how to access other systems with credentials, without having them in the code.
Well you have a couple of options here:
1. Storing the credentials somewhere else
This is the most obvious and easiest approach. Removing the credentials from code, but leaving them in the clear in another file, that is read during runtime and contains the credentials.
The application runs in a user context, therefore the file must be readable by the user, the application is running as. Forbid everyone else and you already have a very basic security. At least more than in code.
Make sure, to never check it in or you haven't won anything.
2. Encrypting it in the code
With encryption you can choose between symetric and asymetric ... or (like in S/MIME) use a combination of both.
No matter how you decide, there will be always the question, how to secure the parameters for encryption. If you save them in the code, you could have saved your credentials in the clear.
Well, if you choose asymetric, there is a way by using X509Certificate2
.
First of all, asymetric is not cheap, that's one of the reasons S/MIME uses a combination of both. But, since we have only very small amounts of data (credentials usually are much less that 1 kb), we still can use it.
This little class of mine takes the properties from a directly derived class and stores them into an asymetrically encrypted base64-string or a BSON encoded asymetrically encrypted Stream.
There is a readme, showing how to use it.
It served me very well! Rest in peace little helper. ... but now we use another option:
3.Azure Key Vault
When runnig in Azure loading from an Azure Key Vault is as easy as these few lines.
private static T LoadFromKeyVault<T>(ref T creds, string credentialName, string version)
where T : class, new()
{
if (creds == null)
{
var astp= new AzureServiceTokenProvider();
var kvc = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(
astp.KeyVaultTokenCallback)
);
var secret = kvc.GetSecretAsync("https://<YourKeyVaultName>.vault.azure.net/",
credentialName,
version).Result;
creds = JsonConvert.DeserializeObject<T>(secret.Value);
}
return creds;
}
You manage the access in the KeyVault itself with Managed Identites.
So only allowed and managed Principals (Users/Apps) are able to get to your precious credentials while TLS secures the transport.
Great read! I have a question though that is yet to be answered. Even if I encrypt the credentials in the source code (when azure is off the table), can’t a malevolent hacker steal the encrypted credentials and use them to access the underlying systems the exact same way as the source code does?