44

I have added the following settings inside my web.config file to initiate an API call to external system. So I am storing the API URL + username + password as follows:-

<appSettings>
    <add key="ApiURL" value="https://...../servlets/AssetServlet" />
    <add key="ApiUserName" value="tmsservice" />
    <add key="ApiPassword" value="test2test2" /> 

Then inside my action method I will be referencing these values when building the web client as follows:-

public ActionResult Create(RackJoin rj, FormCollection formValues)
        {
           XmlDocument doc = new XmlDocument();
           using (var client = new WebClient())
                {
                    var query = HttpUtility.ParseQueryString(string.Empty);
                    foreach (string key in formValues)
                    {
                        query[key] = this.Request.Form[key];
                    }

                    query["username"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiUserName"];
                    query["password"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiPassword"];

                    string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];

But in this was I will be exposing the username and password and these can be captured by users, so my question is how I can secure the API username and password?

Kols
  • 3,641
  • 2
  • 34
  • 42
John John
  • 1
  • 72
  • 238
  • 501
  • This link mayb help: https://www.infoq.com/articles/Secure-web.config – QMaster Feb 26 '19 at 22:58
  • Possible duplicate of [Keeping sensitive information (username & password) in web.config?](https://stackoverflow.com/questions/36472006/keeping-sensitive-information-username-password-in-web-config) – Michael Freidgeim Aug 18 '19 at 02:15
  • For modern recommendations see SCOTT HANSELMAN’s post [Best practices for private config data and connection strings in configuration in ASP.NET and Azure](https://www.hanselman.com/blog/BestPracticesForPrivateConfigDataAndConnectionStringsInConfigurationInASPNETAndAzure.aspx) – Michael Freidgeim Aug 18 '19 at 02:16

6 Answers6

27

You can encrypt the web.config with aspnet_regiis. This is to stop people with access to your server from reading sensitive information.

By the way, I would put your config settings inside a class, that can then be injected into your controllers - it will make unit testing easier.

Joe Ratzer
  • 18,176
  • 3
  • 37
  • 51
  • 1
    but my worry is that system users will be able to capture these sensitive data, and not the users how can access the server. so u mean that web.config data are secure by default ? – John John Jan 03 '14 at 16:50
  • 2
    It is secure by default - IIS will stop web users viewing it. However, you may have a web page that displays parts of the web.config, or you might be hosting it somewhere that requires sensitive information to be encrypted. – Joe Ratzer Jan 03 '14 at 16:53
  • 1
    no i am not displaying these data on any web page. but i still need to use https. so that system users will not be able to capture the web.config data using plugin installed in their browsers such as firegug, fiddler tools .. is that the case? – John John Jan 03 '14 at 16:57
  • 1
    They will not be able to capture the web.config. – Joe Ratzer Jan 03 '14 at 17:07
  • 1
    So what, what if someone hacks the server and navigates to the web.config and does a right-click edit in Notepad. Now what? – Yusha May 21 '18 at 20:39
  • @Yusha - if the web.config is encrypted then opening it in Notepad isn't going to magically decrypt the details. So encrypting your web.config is still sensible in some scenarios. – Joe Ratzer May 22 '18 at 08:12
  • A encrypted web.config file is useless, how would IIS read any of the settings from it if the literal config was encrypted. Are you saying you would encrypt it after deploying changes to the web.config and decrypt it manually each time you wanted to republish the Web.config? – Yusha Oct 03 '18 at 17:48
  • @Yusha for the first question (Scenario about hacking the server) if hacker access stored the machine or user key of [Protected Configuration Provider] can be able to decrypt the encrypted web.config file. But this is an exceptional scenario unless you doubt Hosting company Employees! For second comment you should know decryption process will handle by the .net engine in runtime but if you want to change web.config must decrypt it, change and then encrypt again. – QMaster Mar 10 '19 at 12:46
  • Please read these two valuable documents: https://learn.microsoft.com/en-us/aspnet/identity/overview/features-api/best-practices-for-deploying-passwords-and-other-sensitive-data-to-aspnet-and-azure and https://learn.microsoft.com/en-us/previous-versions/msp-n-p/ff647398(v=pandp.10) – QMaster Mar 10 '19 at 12:46
15

Generally, web.config is a secure file and IIS does not serve it, therefore it will not be exposed to users who are making requests to web server. Web server only serves specific type of files and web.config is surely not one of 'em.

Quite often you save your database connection string in it which includes password. Now imagine an scenario where web.config was not secure. You have created a major security threat to your application.

Therefore, specially as long as your project is not too big, you should not be worrying about it.

Yet, you may have a better approach but creating a project called "Resources" and save all the critical information such as settings, consts, enums and etc in there. That would be a slick and organized approach.

If you are passing the username/password over the wire though (for example in case of a secured API call), you may want to use https to make sure that information that are travelling are encrypted but that has nothing to do with the security of web.config file.

David Silva-Barrera
  • 1,006
  • 8
  • 12
JC Lizard
  • 1,050
  • 6
  • 17
  • so i only need to deploy my web application under https so that web.config data will be encrypted, and system users will not be able to capture these data using firebug or fiddler tool ??? – John John Jan 03 '14 at 16:55
  • 5
    web.config security has nothing to do with https. if you are sending/receiving the data over wire, then that's where https comes to play. if you are using the information on web.config only on your server, you don't need to do anything and you are good to go. what i see above is that you are in fact sending information over wire which sure does need http, but that has nothing to do with web.config security. you can be getting that info from a class propert. so you are talking about 2 absolutely different areas. – JC Lizard Jan 03 '14 at 16:57
  • so you mean that system users will not be able to capture the web client data which is created inside my asp.net web application ? – John John Jan 03 '14 at 16:58
  • 2
    correct, users dont have access to the processes of information that is happening on your server. once all the processes are done, server serves the user with the result which normally is the html content along with js, images, css and etc. – JC Lizard Jan 03 '14 at 17:01
  • 62
    I disagree with the statement "you should not be worrying about [security of passwords]". I worry constantly about plaintext usernames and passwords in web.config. I've put a step in our deployment scripts to encrypt production web.config using aspnet_regiis. Just because IIS won't serve web.config doesn't mean someone won't somehow hack your server and just read the file using, say, System.IO and display it. IMO this should not be at the accepted answer as it recommends not caring about security. – stevieg May 26 '15 at 00:58
  • 5
    I flag any occurrence of credentials stored in plaintext files whenever we do source code review as a security risk. – Casey Jul 21 '15 at 20:48
  • 11
    What a horrible answer - no wonder there are so many insecure IIS and ASP.NET apps out in the wild. The correct answer is to store your secrets outside of the webroot and encrypted, per the second answer below. – nikcub Jan 14 '16 at 23:16
  • application in ASP.net, for the webconfig has a webform with username,pass,host,dbname and it will create .txt file which i will address in webconfig it will be connect but i need to know how it's done (aspnet_regiis.exe -pef) is giving some info but if any advance develper could help ... thanks in advance , just add my name so i get notify really need the help – SAR Jan 01 '17 at 11:46
  • 5
    There is another problem with this answer, and that is that web.config normally is stored in a source control system and therefore copied around to individual development environments. To avoid passing passwords around, you could use apsettings to include a password file, for instance. Production passwords could then be stored on the production machine only. – tobbenb3 Feb 14 '17 at 13:27
6

I know this may sound like over engineering, but if you can, you really should use a secret management service, such as AWS Secrets Manager or Azure Key Vault.

By storing your passwords, even in encrypted form, in your web.config or app.config, you creating several problems for yourself:

  • now your encrypted passwords are going to be committed to your source control, making them accessible to anyone with the read access. To get rid of them properly, you'll need to do a history rewrite (if you are using git) which is a major pain
  • while you technically can put your passwords in the machine-level config, and outside of the source control, you'll need to update all those files when your password changes
  • anyone who's got your encrypted password now can try to decrypt it, using either aspnet_regiis.exe tool (if that's what you used to encrypt it), or if you rolled your own security, reverse engineer that using your source code, figuring out what decryption algo & key it is using
  • whenever you need to change a password, you'll need to make changes to that file & re-deploy the application.

On the other hand, when you use a secret management service, no secrets or decryption key or algorithm is stored in your source code. Retrieving a secret is as simple as this:

For Azure Key Vault:

var keyVaultUrl = "https://<your-key-vault-name>.vault.azure.net/";
var credential =  new DefaultAzureCredential();    
var client = new SecretClient(vaultUri: new Uri(keyVaultUrl), credential);    
KeyVaultSecret secret = client.GetSecret("<your-secret-name>");    
Console.WriteLine($"{secret.Name}: {secret.Value}");

For AWS Secrets Manager (skipped some error handling code):

var client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey, 
                                            RegionEndpoint.APSoutheast2);
var request = new GetSecretValueRequest {
    SecretId = secretName
};
GetSecretValueResponse response = null;
response = client.GetSecretValueAsync(request).Result;

This approach has lots of advantages over storage of local secrets:

  • you don't have to mess with storing different values in configs for Prod/Staging/Dev environments -- just read appropriately named secrets (such as '[Dev|Prod|Stag]DBPassword`
  • only selected few people can have access to the very important secrects (such as, I dunno, say Transfer all $$$ from Deus account to all E-Coin wallets everywhere authorisation code)
  • if anyone steals your source code (disgruntled employee, accidental leak) non of your passwords have been leaked
  • changing a password is easy -- you just update it using the could management console and restart the app(s)

I have written a couple of articles, showing how to set up and read secrets with AWS and Azure on my blog, feel free to check it out if you need step-by-step directions and complete source code:

Art
  • 23,747
  • 29
  • 89
  • 101
  • To use these *secret management tools* we have to use an API_KEY to get key-value pairs. So where do we save secret management's API_KEY? – Mohammad Barbast Nov 24 '21 at 13:33
  • @MohammadBarbast the API_KEY can be stored in the same type of vault (depending on your cloud platform) and retrieved from there by your build agent, to be placed in the container env variables. This way it still stays out of the source code and you can change it quickly in case of a breach. – Art Nov 25 '21 at 22:21
  • So, What credentials we have to provide to get API_KEY? – Mohammad Barbast Feb 27 '22 at 18:15
  • @MohammadBarbast you don't. Your build agents are supposed to be spun up having appropriate access to the AWS/Azure account already. – Art Jun 20 '23 at 04:13
3

The web.config file is just a file on the file system and so you should (mostly) consider its security in the same way as you would any other file. It will not be served by IIS (unless you make a frankly insane config change to IIS - easy to check for, just try and request it with a browser)

It is good practice to secure your website directory (c:/sites/my-site-here or whatever) using folder permissions to just the website app domain user to read the files (and the deployment user if needed) by using normal windows file permissions

So it may not be necessary to encrypt if you have confidence in the security of the web server. However if you are say on shared hosting, or selling the website code, or the source code is public, then it might be wise to encrypt it. it is a little bit hassle some though.

alastairtree
  • 3,960
  • 32
  • 49
  • 4
    can you explain more you point. so u mean that it is not essential to encrypt sensitive data inside web.config – John John Jan 03 '14 at 16:51
3

Why use Web.config?

One of the advantages of having data in Web.config as opposed to storing it in Constants, Enums, etc... is that you can change the data for different environments easily.

Protecting data

The best way to secure the data in Web.config is to encrypt them. Instead of encrypting entire sections in the config file as suggested by Joe and user1089766 you can just encrypt the password string and store it in the config.

Retrieving data

You can use a helper function such as the one below to decrypt the keys.

private const readonly string decryptKey = "";
public string GetFromConfig(string key)
{
   var encryptedText = System.Web.Configuration.WebConfigurationManager.AppSettings[key];
   var plainText = Decrypt(encryptedText, decryptKey);
   return plainText;
}

In this way the decryption key will be inside the project common for all environments. But you can change the data in the web.config easily without recompiling your app.

PS: You can change the decryptionKey and the corresponding data with each version to improve security.

Kols
  • 3,641
  • 2
  • 34
  • 42
1

I have to encourage you to separate the code from the Keys. Even if you encrypt the file, someone can clone it from your repo and while it is encrypted, you may no longer be able to track the file, or may get access to a key in the future, etc.

Plus as Art indicated (and maybe others in the thread) this makes it is really easy to have a separate set of keys for Dev / Test / Prod / etc. If you encrypt the file, sounds like you are going to either have the same encrypted data and decryption key in all of these environments. You won't necessarily have an easy way to change in one but not the others.

Think about the long game - not just passwords but other configuration information should be loaded and unique per environment (API Keys, etc.)

We use this approach for developers too. I don't want each developer to have their own API key, passwords, etc so they don't have access to systems they don't need. I can shutdown a user's API key if a development laptop is lost. I can rotate dev / test / prod API keys and only have to worry about changing in one place, not inform all users that a file has been updated and they need to re-clone.

Gary
  • 71
  • 2