Skip to content

C# Secret Management

c# secret management
Lost in coding? Discover our Learning Paths!
Lost in coding? Discover our Learning Paths!

In this article we will talk about C# secret management.

Sensitive data leakage

Sensitive information that shouldn’t be stored in source code. Different sorts of credentials, API keys, SSH keys, encryption keys, database passwords, are examples of sensitive information that should be avoided from being leaked into source code.

Why not hard-coding sensitive data?

Storing sensitive data such as passwords in source code makes the application vulnerable to security attacks. One of the reasons is that most of the time not all developers need to know all credentials. Even if all developers are allowed to access all credentials, development environments, deployment pipelines, and servers are not designed to keep hard coded secrets safe. Another issue with hard-coding passwords is that the administrator would be unable to change the secrets at runtime. He may be forced to disable the product entirely in case of secret theft.

How to Store Sensitive Data for Development?

Sensitive data should be stored in a different location from the project tree. Source code is best not to depend on the location or format of the data because they may change. Secret Manager is a tool that stores sensitive data during the development of ASP.NET projects, and hides implementation details such as location and format of the data being stored.

Let’s quickly see it in action.

Step by Step Guide to C# Secret Management

Let’s create an empty web project first

Now let’s open the project using an IDE.

And to enable secret storage let’s run the init command in the project’s directory:

Now let’s set a new secret

To check if the secret is stored successfully I can list all secrets.

The list currently contains a single secret.

The secret is stored successfully. But how to access it from code?

Let’s open the Program.cs file.

Let’s read the secret we just stored using the configuration API, and show its value as the root of the web API is requested.

And run it. Now I can see the secret’s value in the browser.

 

Mapping Secrets to Dotnet Classes

The secret can also be directly mapped to the properties of a simple dotnet class.

Let’s create a new class named “Settings”, and add a property with the same name as the secret’s key.

Let’s open the Program.cs file again, and load the configuration section containing the secret into the Settings file. And reveal the secret by the web API.

Accessing Secrets From a Controller

Let’s add a controller named SecretController with an action which returns an empty string.

The Program.cs file should look like this:

To returns the secret let’s inject the Settings class we built in previous section to the controller’s constructor and instead of returning the empty string return the secret’s value.

We should also configure the web application from Program.cs file. The Settings class should be added to the service collection.

Let’s run the application and open the /controller route in the browser to see the secret.

Storing Connection String Passwords

Rather than storing passwords to database connection strings in plain text in configuration files, I would omit the password from connection strings, and store the password using Secret Manager. To add the password to a connection string at run time I would use the Configuration API to load both the connection string and its password individually. I can then use the ConnectionStringBuilder class to add the password to the connection string at run time.

Let’s see it in action. Let’s open the appsettings.json file, and add a connection string to it.

And remove the password from the connection string

And add it to the user’s secrets.

To read the connection string let’s open the Program.cs file, and read the connection string, the password, add the password to the connection string, and finally reveal it on the web.

Now let’s run it, switch to constr route, and this is the complete connection string containing the password.

Removing Secrets

To remove a secret go to project’s folder and run this command:

Clearing All Secrets

To clear all secrets go to the project’s folder and run this command:

Where Are The Secrets Stored Physically?

Whenever I call dotnet user-secrets set ... the secret is stored in a secrets.json file by default. secrets.json file is stored in the local machine’s user profile folder:

 

Linux/macOS ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
Windows %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

To find the <user_secrets_id> let’s open the project’s file. A new element is added under the <PropertyGroup> when I ran dotnet user-secrets init. It contains an arbitrary GUID.

To open the secrets.json file replace <user_secrets_id> with the GUID. This id connects the secrets.json file to the app. Both Secret Manager and Configuration API use this GUID to find the secrets.json file which belongs to your application.

Summary

Storing sensitive data in the project tree creates a significant whole that allows attackers’ access to the data. Storing the data to a file with a custom path outside of the project tree and hard-coding it’s address on the other hand couples application to the platform.

Dotnet’s Secret Manager tool provides a simple command line interface for developers to store their development time secrets to files that Configuration API loads them by default.

Configuration API provides a simple interface that decouples configuration data from its source so that the data source can be changed without the need to change the source code.

Consequently developers can store secrets to secrets.json and read it using Configuration API. In production the secret’s data source can be whatever as long as a configuration provider loads it and makes it accessible through Configuration API.

Different databases must have different passwords in different machines for example, but this requirement shouldn’t require the source code to be changed for each machine.

Lost in coding? Discover our Learning Paths!
Lost in coding? Discover our Learning Paths!
Become a senior C# developer and build software like an A-Player
Join the C# Progress Academy and master C# .NET, ASP.NET, Design Patterns, Asynchronous Development, Clean Code, and much more.
Become a senior C# developer and build software like an A-Player
Join the C# Progress Academy and master C# .NET, ASP.NET, Design Patterns, Asynchronous Development, Clean Code, and much more.