Join the social network of Tech Nerds, increase skill rank, get work, manage projects...
 
  • How to Store Sensitive Data in ASP.NET Core - UserSecrets

    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 3
    • 0
    • 2.10k
    Comment on it

    A most important part of developing an application which when pushed to any public source code repository is that sensitive data should not be stored within source code as other users may develop crawlers in order to find passwords, usernames and other secret stuff in the pushed project. This sensitive data (developer's secrets) is termed as UserSecrets.

     

     

    Following are some scenario's where a developer can have sensitive data:-

    • Social Media like Facebook, Twitter etc API key should be a secret key which is used while development. These API keys are secret keys, therefore, there is no need to place them within the source code.
    • To access database user-specific passwords should not be exposed.
    • Credentials for accessing services like mail servers, FTP etc should be kept a secret.

     

    To store this kind of sensitive data in ASP.NET Core "Secret Manager" tool is used. This tool is capable of storing sensitive stuff for development outside of project structure. With the help of this tool app secrets can be associated with the specific project and share these app secrets among several projects. Therefore, it can be considered a very elegant way of keeping development secrets to themselves only.


    Note:- The "Secret Manager" tool is only capable of storing sensitive data outside project structure but does not store this data in encrypted form thus cannot be considered as a trusted store. It can be used for development purpose only where keys and values are stored in JSON configuration file.

     

    Following are the packages to be downloaded from NuGet in order to store sensitive data:-

     

    • Microsoft.Extensions.Configuration.UserSecrets
    • Microsoft.Extensions.SecretManager.Tools

     

    After downloading these packages right click on the project in solution explorer and select "Manage User Secrets" which opens a file "secrets.json". This action causes the addition of a new "UserSecretsId" in "project.json" file. This "UserSecretsId" is a unique identifier which keeps user related secrets.


    After performing above steps, "project.json" file is as follows:-

     

    {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "version": "1.0.1",
          "type": "platform"
        },
        "Microsoft.ApplicationInsights.AspNetCore": "1.0.0",
        "Microsoft.AspNetCore.Diagnostics": "1.0.0",
        "Microsoft.AspNetCore.Mvc": "1.0.1",
        "Microsoft.AspNetCore.Razor.Tools": {
          "version": "1.0.0-preview2-final",
          "type": "build"
        },
        "Microsoft.AspNetCore.Routing": "1.0.1",
        "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
        "Microsoft.AspNetCore.StaticFiles": "1.0.0",
        "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
        "Microsoft.Extensions.Configuration.Json": "1.0.0",
        "Microsoft.Extensions.Logging": "1.0.0",
        "Microsoft.Extensions.Logging.Console": "1.0.0",
        "Microsoft.Extensions.Logging.Debug": "1.0.0",
        "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
        "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
        "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0"
      },
    
      "tools": {
        "BundlerMinifier.Core": "2.0.238",
        "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final",
        "Microsoft.Extensions.SecretManager.Tools": "1.0.0"
      },
    
      "frameworks": {
        "netcoreapp1.0": {
          "imports": [
            "dotnet5.6",
            "portable-net45+win8"
          ]
        }
      },
    
      "buildOptions": {
        "emitEntryPoint": true,
        "preserveCompilationContext": true
      },
    
      "runtimeOptions": {
        "configProperties": {
          "System.GC.Server": true
        }
      },
    
      "publishOptions": {
        "include": [
          "wwwroot",
          "**/*.cshtml",
          "appsettings.json",
          "web.config"
        ]
      },
    
      "scripts": {
        "prepublish": [ "bower install", "dotnet bundle" ],
        "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
      },
      "userSecretsId": "aspnet-AspNetCoreUserSecrets-20180102030556"  //UserSecretsId
    }
    

     

    Adding the user secrets configuration to the Startup method

     

    Open "Startup.cs", within "Startup" method add "AddUserSecrets()" to ConfigurationBuilder for keeping secrets. 

     

    Startup.cs

     

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    
    namespace AspNetCoreUserSecrets
    {
        public class Startup
        {
            public Startup(IHostingEnvironment env)
            {
                var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
    
                if (env.IsDevelopment())
                {
                    // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
                    builder.AddApplicationInsightsSettings(developerMode: true);
                    builder.AddUserSecrets(); // for keeping user secrets
                    
                }
                Configuration = builder.Build();
            }
    
            public IConfigurationRoot Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                services.AddApplicationInsightsTelemetry(Configuration);
                services.AddMvc();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
    
                app.UseApplicationInsightsRequestTelemetry();
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseBrowserLink();
                    
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseApplicationInsightsExceptionTelemetry();
    
                app.UseStaticFiles();
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    }

     

    There are two ways of adding sensitive data to file named "secrets.json":


    1. Right-click on the project in solution explorer and select "Manage User Secrets" which will open secret json file and add sensitive data to it.


      2. Command line way of dealing with "user-secrets". Open cmd in project location.

     

    •     "dotnet user-secrets -h" shows all commands of "user-secrets".
    •     "dotnet user-secrets list" provides a list of added secrets to the project.
    •     "dotnet user-secrets set <secretkeyname> <secretkey>" for adding a secretkey. This secret key will appear in "secrets.json" file.


    In below screenshot, it can be seen that "secrets.json" file cannot be seen within project structure.

     

     

     

    Location of "secrets.json" 

     

    ASP.NET Core apps are cross-platform, therefore "secrets.json" file can be found in a different location for different platform.

     

    • Windows :- “Secret Manager Tool” add "secrets.json" file in AppData of current logged in Windows users such as "C:\Users\<UserName>\AppData\Roaming\Microsoft\UserSecrets\aspnet-AspNetCoreUserSecrets-20180102030556" where last parameter is the "UserSecretsId" stored in "project.json".

     

    • Non-Windows :-UserSecrets are located at "~/.microsoft/usersecrets/<userSecretsId>/secrets.json".

     

    Accessing UserSecrets in Asp.Net Core application

     

    Add a class named "ExternalProviderApiKeyConfig" within Models folder in project

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace AspNetCoreUserSecrets.Models
    {
        public class ExternalProviderApiKeyConfig
        {
            public string FacebookAPIKey { get; set; }
            public string TwitterAPIKey { get; set; }
        }
    }
    

     

    "secrets.json" file keep secrets keys within a section

    {
      "ApiKeys": {
        "TwitterAPIKey": "XYZ1234ABC",
        "FacebookAPIKey": "XXX12345ABC"
      }
    }

     

    Register the secretkey section in Startup class within ConfigureServices method

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using AspNetCoreUserSecrets.Models;
    
    namespace AspNetCoreUserSecrets
    {
        public class Startup
        {
            public Startup(IHostingEnvironment env)
            {
                var builder = new ConfigurationBuilder()
                    .SetBasePath(env.ContentRootPath)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
    
                if (env.IsDevelopment())
                {
                    // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
                    builder.AddApplicationInsightsSettings(developerMode: true);
                    builder.AddUserSecrets(); // for keeping user secrets
                    
                }
                Configuration = builder.Build();
            }
    
            public IConfigurationRoot Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                services.AddApplicationInsightsTelemetry(Configuration);
                services.Configure<ExternalProviderApiKeyConfig>(Configuration.GetSection("ApiKeys")); //apikey section from secrets.json
                services.AddMvc();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
    
                app.UseApplicationInsightsRequestTelemetry();
    
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                    app.UseBrowserLink();
                    
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
    
                app.UseApplicationInsightsExceptionTelemetry();
    
                app.UseStaticFiles();
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
        }
    }
    

     

    Usage of sensitive data in Controller

     

    HomeController

     

    using Microsoft.AspNetCore.Mvc;
    using AspNetCoreUserSecrets.Models;
    using Microsoft.Extensions.Options;
    
    namespace AspNetCoreUserSecrets.Controllers
    {
        public class HomeController : Controller
        {
            public ExternalProviderApiKeyConfig ApiConfigs { get; }
    
            public HomeController(IOptions<ExternalProviderApiKeyConfig> apikeys)
            {
                ApiConfigs = apikeys.Value;
            }
    
            public IActionResult Index()
            {
                ViewData["TwitterSecretKey"] = ApiConfigs.TwitterAPIKey;  //Now api keys can be used in any controller action
                return View();
            }
        }
    }

     

     

    Running application shows following:-

     

     

     

    How to Store Sensitive Data in ASP.NET Core - UserSecrets

 0 Comment(s)

Sign In
                           OR                           
                           OR                           
Register

Sign up using

                           OR                           
Forgot Password
Fill out the form below and instructions to reset your password will be emailed to you:
Reset Password
Fill out the form below and reset your password: