locked
What is the best place to store sensitive info inside asp.net MVC core web application (appsettings.json OR database) RRS feed

  • Question

  • User-540818677 posted

    I am working on an asp.net MVC web application, and inside my code i am sending email using an SMTP server, and to do so i need to pass the username and password. currently i have the password inside my code, but i am not sure what is the best place to store the password inside asp.net core MVC ? For example inside the appsettings.json or inside the database?

    Tuesday, June 23, 2020 10:45 PM

All replies

  • User475983607 posted

    johnjohn123123

    I am working on an asp.net MVC web application, and inside my code i am sending email using an SMTP server, and to do so i need to pass the username and password. currently i have the password inside my code, but i am not sure what is the best place to store the password inside asp.net core MVC ? For example inside the appsettings.json or inside the database?

    The configuration fundamentals doc covers the how to secure sensitive configuration.

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1

    Tuesday, June 23, 2020 10:51 PM
  • User-2054057000 posted

    You can create a JSON file in the project and in this file you can store your passwords. Like:

    {
        "SMTP": "SomePassword",
        "Database": "SomePass"
    }

    Then you include this JSON file in the Program.cs file and inject them to controllers using Dependency Injection. Kindly Refer - Injecting Values from JSON file to Controllers

    Wednesday, June 24, 2020 4:35 AM
  • User-540818677 posted

    You can create a JSON file in the project and in this file you can store your passwords. Like:

    {
        "SMTP": "SomePassword",
        "Database": "SomePass"
    }

    Then you include this JSON file in the Program.cs file and inject them to controllers using Dependency Injection. Kindly Refer - Injecting Values from JSON file to Controllers

    but can not i just add the password inside the appsettings.json? why i need to create a new json file?

    Wednesday, June 24, 2020 11:38 AM
  • User475983607 posted

    johnjohn123123

    but can not i just add the password inside the appsettings.json? why i need to create a new json file?

    You really should take the time to read the openly published documentation linked in my first post.  The documentation explains several approaches for securing configuration data.  It is up to you to learn the different options then pick an approach that best fits your application security requirements.

    My team uses source control.   The last thing we want is leaking sensitive data like passwords into source control.  We take advantage of user secrets on our development machines and environment variables on the server.   This may or may not be a good solution for you.  But, the first step is knowing your options.

    Wednesday, June 24, 2020 12:03 PM
  • User-540818677 posted

    johnjohn123123

    but can not i just add the password inside the appsettings.json? why i need to create a new json file?

    You really should take the time to read the openly published documentation linked in my first post.  The documentation explains several approaches for securing configuration data.  It is up to you to learn the different options then pick an approach that best fits your application security requirements.

    My team uses source control.   The last think we want leaking sensitive data like passwords into source control.  We take advantage of user secrets on our development machines and environment variables on the server.   This may or may not be a good solution for you.  But, the first step is knowing your options.

    So is storing the password inside the appsettings.json a bad approach or insecure approach? as by default the database connection strings which include the password for the database service account will be stored inside the appsettings.json...

    Wednesday, June 24, 2020 2:05 PM
  • User-2054057000 posted

    but can not i just add the password inside the appsettings.json? why i need to create a new json file?

    Yes you can procedure is same.

    Wednesday, June 24, 2020 2:21 PM
  • User475983607 posted

    So is storing the password inside the appsettings.json a bad approach or insecure approach?

    Typically storing sensitive data like passwords in the appsettings.json is a bad approach.  

    as by default the database connection strings which include the password for the database service account will be stored inside the appsettings.json...

    That's only true if you are using SQL logins.  It's very common to run a web application under a domain account and configure integrated Windows security which does not include a password in the connection string.  However, if you are using SQL login then you should secure the connection string.

    I'm sure you'll be interested in reading the previous links as the docs covers several methods for securing configuration. 

    Wednesday, June 24, 2020 2:32 PM
  • User-474980206 posted

    Most security experts would say that storing internal server names in config files is also a bad practice. So connection strings should be secure even if they don’t have a password.

    Wednesday, June 24, 2020 2:44 PM
  • User-540818677 posted

    Most security experts would say that storing internal server names in config files is also a bad practice. So connection strings should be secure even if they don’t have a password.

    ok understood, but generally speaking who can access the appsettings.json? can public users access it? or only users who can access the host server can do so?

    Thanks

    Wednesday, June 24, 2020 2:56 PM
  • User475983607 posted

    Most security experts would say that storing internal server names in config files is also a bad practice. So connection strings should be secure even if they don’t have a password.

    Agreed, I did not intend to infer it is okay to store a connection string in the appsettings.json.    But after reading my response that exactly what I did.  

    Wednesday, June 24, 2020 3:10 PM
  • User-2054057000 posted

    bruce (sqlwork.com)

    Most security experts would say that storing internal server names in config files is also a bad practice. So connection strings should be secure even if they don’t have a password.

    ok understood, but generally speaking who can access the appsettings.json? can public users access it? or only users who can access the host server can do so?

    Thanks

    Appsettings.json can only be accessed by the application i.e. the public users cannot access it. It's safe to store passwords there.

    Thursday, June 25, 2020 4:46 AM
  • User-540818677 posted

    johnjohn123123

    bruce (sqlwork.com)

    Most security experts would say that storing internal server names in config files is also a bad practice. So connection strings should be secure even if they don’t have a password.

    ok understood, but generally speaking who can access the appsettings.json? can public users access it? or only users who can access the host server can do so?

    Thanks

    Appsettings.json can only be accessed by the application i.e. the public users cannot access it. It's safe to store passwords there.

    Thanks for the reply, but as a second layer of security can not we encrypt specific sections of the appsettings.json?

    Thursday, June 25, 2020 10:04 AM
  • User475983607 posted

    johnjohn123123

    Thanks for the reply, but as a second layer of security can not we encrypt specific sections of the appsettings.json?

    If you feel the security feature in ASP.NET Core are not suitable and you need to create a custom solution then go ahead.  There is nothing stopping you from encrypting a value.  It is up to you to write a utility.  Fortunately, the code is openly published in standard .NET docs.

    https://docs.microsoft.com/en-us/dotnet/standard/security/cryptography-model

    https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=netcore-3.1

    Thursday, June 25, 2020 10:40 AM
  • User-540818677 posted

    johnjohn123123

    Thanks for the reply, but as a second layer of security can not we encrypt specific sections of the appsettings.json?

    If you feel the security feature in ASP.NET Core are not suitable and you need to create a custom solution then go ahead.  There is nothing stopping you from encrypting a value.  It is up to you to write a utility.  Fortunately, the code is openly published in standard .NET docs.

    https://docs.microsoft.com/en-us/dotnet/standard/security/cryptography-model

    https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=netcore-3.1

    i do not want to create something new,,, as i mentioned in the web.config case we used to have the ability to encrypt sections of the web.congig using IIS encryption,,, so can not i do the same with the appsettings.json?

    Thursday, June 25, 2020 10:53 AM
  • User475983607 posted

    i do not want to create something new,,, as i mentioned in the web.config case we used to have the ability to encrypt sections of the web.congig using IIS encryption,,, so can not i do the same with the appsettings.json?

    This feature does not exist in ASP.NET Core.  ASP.NET Core is cross platform and IIS runs on a Windows box.

    It is important to understand that encryption does not solve the problem.  It moves the problem to securing the encryption key.  Anyone that has the key can easily decrypt sensitive data.   

     

    Thursday, June 25, 2020 11:59 AM
  • User-540818677 posted

    This feature does not exist in ASP.NET Core.  ASP.NET Core is cross platform and IIS runs on a Windows box.

    so how i can secure the appsettings.json in this case?

    Thursday, June 25, 2020 12:45 PM
  • User475983607 posted

    so how i can secure the appsettings.json in this case?

    I'm not sure how to help you.  It seems you are not willing to use standard ASP.NET Core configuration and you are not willing to write your own.  I built an encrypt/decrypt service that you can play around with.

    appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "password": "VCEzsHhZrb8jD/yyDIvzWw=="
    }

    Controller

    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly IAesCryptoUtil _aesCryptoUtil;
        private readonly IConfiguration _configuration;
    
        public HomeController(
            ILogger<HomeController> logger,
            IAesCryptoUtil aesCryptoUtil,
            IConfiguration configuration)
        {
            _logger = logger;
            _aesCryptoUtil = aesCryptoUtil;
            _configuration = configuration;
        }
    
        [HttpGet]
        public ActionResult Index()
        {
            string encryptedValue = _configuration["password"];
            string password = _aesCryptoUtil.Decrypt(encryptedValue);
            return Content(password);
        }
    }

    Service code based on the AES encryption shared above or in your other thread with the same subject.

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Threading.Tasks;
    
    namespace MvcBasic.Crypto
    {
        public interface IAesCryptoUtil
        {
            string Decrypt(string base64String);
            string Encrypt(string text);
        }
    
        public class AesCryptoUtil : IAesCryptoUtil
        {
            private byte[] Key;
            private byte[] IV;
    
            public AesCryptoUtil()
            {
                Key = new byte[] {
                    0x2F, 0xFA, 0x72, 0x68, 0x7, 0x3C, 0xF6, 0xCC, 0x18, 0x8E, 0x20, 0xD7, 0x7E, 0x71, 0x20, 0x7E, 0x65, 0x98, 0xDB, 0xCE, 0xDF, 0x8, 0xE5, 0x57, 0x95, 0xB0, 0xDB, 0xC1, 0x83, 0x41, 0x15, 0x6A
                };
    
                IV = new byte[] { 0x96, 0xA0, 0x20, 0xA5, 0xD6, 0x43, 0xC8, 0x9D, 0xB1, 0x7E, 0x8D, 0xCE, 0xA1, 0x9F, 0x35, 0xFD };
            }
    
            public string Encrypt(string text)
            {
                byte[] buff = EncryptStringToBytes_Aes(text);
                return Convert.ToBase64String(buff);
            }
    
            public string Decrypt(string base64String)
            {
                byte[] buff = Convert.FromBase64String(base64String);
                return DecryptStringFromBytes_Aes(buff);
            }
    
            private byte[] EncryptStringToBytes_Aes(string plainText)
            {
                // Check arguments.
                if (plainText == null || plainText.Length <= 0)
                    throw new ArgumentNullException("plainText");
                if (Key == null || Key.Length <= 0)
                    throw new ArgumentNullException("Key");
                if (IV == null || IV.Length <= 0)
                    throw new ArgumentNullException("IV");
                byte[] encrypted;
    
                // Create an Aes object
                // with the specified key and IV.
                using (Aes aesAlg = Aes.Create())
                {
                    aesAlg.Key = Key;
                    aesAlg.IV = IV;
    
                    // Create an encryptor to perform the stream transform.
                    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
    
                    // Create the streams used for encryption.
                    using (MemoryStream msEncrypt = new MemoryStream())
                    {
                        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                            {
                                //Write all data to the stream.
                                swEncrypt.Write(plainText);
                            }
                            encrypted = msEncrypt.ToArray();
                        }
                    }
                }
    
                // Return the encrypted bytes from the memory stream.
                return encrypted;
            }
    
            private string DecryptStringFromBytes_Aes(byte[] cipherText)
            {
                // Check arguments.
                if (cipherText == null || cipherText.Length <= 0)
                    throw new ArgumentNullException("cipherText");
                if (Key == null || Key.Length <= 0)
                    throw new ArgumentNullException("Key");
                if (IV == null || IV.Length <= 0)
                    throw new ArgumentNullException("IV");
    
                // Declare the string used to hold
                // the decrypted text.
                string plaintext = null;
    
                // Create an Aes object
                // with the specified key and IV.
                using (Aes aesAlg = Aes.Create())
                {
                    aesAlg.Key = Key;
                    aesAlg.IV = IV;
    
                    // Create a decryptor to perform the stream transform.
                    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    
                    // Create the streams used for decryption.
                    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {
    
                                // Read the decrypted bytes from the decrypting stream
                                // and place them in a string.
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }
    
                return plaintext;
            }
        }
    }
    

    DI service registration in startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.AddSingleton<IAesCryptoUtil, AesCryptoUtil>();
    }

    The password is 123abc.

    Encrypt and Decrypt actions let you encrypt and decrypt values which can be used as a utility for testing.  Don't put the actions in production.

    https://localhost:44358/home/encrypt?value=123abc
    https://localhost:44358/home/decrypt?value=VCEzsHhZrb8jD/yyDIvzWw==

    Thursday, June 25, 2020 2:25 PM