Skip to content
Vignesh Blog
Go back

How to use data redaction in .net core web api

blog image

Table of contents

Open Table of contents

Intro

Applying masking or obscuring your sensitive data in logs, error messages or other sources keeps us in compliance with privacy rules and protects sensitive data.

We will be walking through, step by step, how to achieve this in a .NET Core Web API.

Step 1 - Packages required

dotnet add package Microsoft.Extensions.Compliance.Redaction
dotnet add package Microsoft.Extensions.Telemetry
dotnet add package Microsoft.Extensions.Telemetry.Abstractions

Step 2 - Defining your data classification

We need to classify our data to apply the appropriate attributes for the data.

Below the class, specify a classification

public static class MyTaxonomyClassifications
{
 public static string Name => "MyTaxonomy";
 public static DataClassification Private => new(Name, nameof(Private));
}

After data classification, next step is to create an attribute to use in our DTO classes

public sealed class PrivateDataAttribute : DataClassificationAttribute
{
 public PrivateDataAttribute() : base(MyTaxonomyClassifications.Private) { }
}

Step 3 - Applying in User Data

We have a user class that has an email ID; in order to protect the sensitive information, we apply the attribute PrivateDataAttribute

public record User(string Name, int Age, [PrivateData] string Email);

Step 4 - Defining the Redactor

By default, we have the ErasingRedactor that replaces any input with an empty string and the HmacRedactor uses HMACSHA256 to encode data being redacted.

For this, we use a custom star redactor which replaces the string with stars; it should inherit the Redactor

public sealed class StarRedactor : Redactor
{
 private const string Stars = "****";

 public override int GetRedactedLength(ReadOnlySpan<char> input) => Stars.Length;

 public override int Redact(ReadOnlySpan<char> source, Span<char> destination)
 {
 Stars.CopyTo(destination);

 return Stars.Length;
 }
}

Step 5 - Registering the Redactor configuration

Register our custom redactor in the service collection

builder.Services.AddRedaction(options =>
{
 // Configure redaction options here if needed
 options.SetRedactor<StarRedactor>(MyTaxonomyClassifications.Private);
});

It is important to enable redaction in Logging to mask sensitive information

builder.Services.AddLogging(builder =>
{
 // Enable redaction.
 builder.EnableRedaction();
});

We are adding JSON console in order to view the state of our object is sanitized by our custom redactor, as the default console logger does not show the state. In Azure Application Insights you will be able to see the masking in the custom properties.

builder.Logging.AddJsonConsole(options =>
{
 options.JsonWriterOptions = new System.Text.Json.JsonWriterOptions { Indented = true };
});

Step 6 - Defining the Logger extension methods

By default, the logger doesn’t validate the attributes; to enforce them, we should annotate the respective object with LogProperties.

Here we define a custom extension for the User object

public static partial class LogExtensions
{
 [LoggerMessage(
 EventId = 5001,
 Level = LogLevel.Information,
 Message = "Processing request for user")]
 public static partial void LogUserRegistrationAttempt(
 this ILogger logger,
 [LogProperties] User user);
}

Step 7 - Final Step

Everything is wired up now. In order to test the sanitization of sensitive data, create the POST endpoint below which will receive the User data and log it.

app.MapPost("/user", (User user, ILogger<User> logger) =>
{
 // Process the user data here
 logger.LogUserRegistrationAttempt(user);
 return Results.Ok(user);
}).WithName("CreateUser").WithOpenApi();

Supplied a sample request

{
 "name": "John",
 "age": 24,
 "email": "[email protected]"
}

In the console, we are able to see the state of the data is sanitized for the sensitive information.

{
 "EventId": 5001,
 "LogLevel": "Information",
 "Category": "User",
 "Message": "Processing registration request for user",
 "State": {
 "Message": "Microsoft.Extensions.Logging.ExtendedLogger\u002BModernTagJoiner",
 "user.Email": "****", -> `Data is masked`
 "user.Age": 24,
 "user.Name": "John",
 "{OriginalFormat}": "Processing registration request for user"
 }
}

Final thoughts

This example is generated in order to give a basic understanding of redaction in a .NET Core Web API, for more in-depth understanding, please refer MS Docs


Share this post:

Next Post
What is hybrid cache and why should you use it