Serilog.Enrichers.Sensitive
1.7.2
See the version list below for details.
dotnet add package Serilog.Enrichers.Sensitive --version 1.7.2
NuGet\Install-Package Serilog.Enrichers.Sensitive -Version 1.7.2
<PackageReference Include="Serilog.Enrichers.Sensitive" Version="1.7.2" />
paket add Serilog.Enrichers.Sensitive --version 1.7.2
#r "nuget: Serilog.Enrichers.Sensitive, 1.7.2"
// Install Serilog.Enrichers.Sensitive as a Cake Addin #addin nuget:?package=Serilog.Enrichers.Sensitive&version=1.7.2 // Install Serilog.Enrichers.Sensitive as a Cake Tool #tool nuget:?package=Serilog.Enrichers.Sensitive&version=1.7.2
Serilog.Enrichers.Sensitive
This is a Serilog enricher that can mask sensitive data from a LogEvent
message template and its properties. Currently this supports e-mail addresses and IBAN numbers but could easily be extended to other types of data.
There are two ways of using this enricher:
- Always mask sensitive data (default behaviour)
- Mask data in sensitive areas only
See Usage below on how to configure this.
Possible use case
Let's say you have written a request/response logging middleware for ASP.Net Core that outputs:
Request start {method} {url}
End {method} {status_code} {url} {duration}
Here you have the potential that the url
property contains sensitive data because someone might do GET /api/users/?email=james.bond@universalexports.co.uk
.
Of course you can write your logging middleware to capture this and that may be the best place in this situation. However there might be cases where you don't know this is likely to happen and then you end up with the e-mail address in your logging platform.
When using this enricher what you will get is that the log message that used to be:
Request start GET /api/users/?email=james.bond@universalexports.co.uk
will be:
Request start GET /api/users/?email=***MASKED***
It does not end here
Even though that you know the sensitive data will be masked, it is good practice to not log sensitive data at all.
The good thing is that with the masking applied you can add an alert to your logging platform that scans for ***MASKED***
and gives you feedback when sensitive data has been detected. That allows you to fix the problem where it originates (the logging middleware).
Usage
Always mask sensitive data
Configure your logger with the enricher:
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMasking()
.WriteTo.Console()
.CreateLogger();
If you then have a log message that contains sensitive data:
logger.Information("This is a sensitive {Email}", "james.bond@universalexports.co.uk");
the rendered message will be logged as:
This is a sensitive ***MASKED***
the structured log event will look like (abbreviated):
{
"RenderedMessage": "This is a sensitive ***MASKED***",
"message": "This is a sensitive {Email}",
"Properties.Email": "***MASKED***"
}
Mask in sensitive areas only
Configure your logger with the enricher:
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMaskingInArea()
.WriteTo.Console()
.CreateLogger();
in your application you can then define a sensitive area:
using(logger.EnterSensitiveArea())
{
logger.Information("This is a sensitive {Email}", "james.bond@universalexports.co.uk");
}
The effect is that the log message will be rendered as:
This is a sensitive ***MASKED***
See the Serilog.Enrichers.Sensitive.Demo app for a code example of the above.
Configuring masking operators to use
By default the enricher uses the following masking operators:
- EmailAddressMaskingOperator
- IbanMaskingOperator
- CreditCardMaskingOperator
It's good practice to only configure the masking operators that are applicable for your application. For example:
new LoggerConfiguration()
.Enrich
.WithSensitiveDataMasking(
options =>
{
options.MaskingOperators = new List<IMaskingOperator>
{
new EmailAddressMaskingOperator(),
new IbanMaskingOperator()
// etc etc
};
});
It is also possible to not use any masking operators but instead mask based on property names. In that case you can configure the enricher to not use any masking operators at all:
new LoggerConfiguration()
.Enrich
.WithSensitiveDataMasking(
options =>
{
options.MaskingOperators.Clear();
});
Using a custom mask value
In case the default mask value ***MASKED***
is not what you want, you can supply your own mask value:
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMasking(options => options.MaskValue = "**")
.WriteTo.Console()
.CreateLogger();
A example rendered message would then look like:
This is a sensitive value: **
You can specify any mask string as long as it's non-null or an empty string.
Customising the mask value based on the matched value
In situations where you want to change the mask and have it include parts of the matched value you can override the PreprocessMask
method that takes both mask
and match
parameters. This allows you to perform more masks that are more dynamic.
For example: mask only the "user" part of an e-mail address.
public class CustomizedEmailAddressMaskingOperator : EmailAddressMaskingOperator
{
protected override string PreprocessMask(string mask, Match match)
{
var parts = match.Value.Split('@');
return mask + "@" + parts[1];
}
}
When the mask is ***MASKED***
and we pass in james.bond@universalexports.co.uk
the result will be ***MASKED***@universalexports.co.uk
.
Note that this example uses EmailAddressMaskingOperator
which has a fairly complex regular expression. If possible change your regular expression to have match groups so you can more easily access them through the match
parameter.
Always mask a property
It may be that you always want to mask the value of a property regardless of whether it matches a pattern for any of the masking operators. In that case you can specify that the property is always masked:
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMasking(options => options.MaskProperties.Add("email"))
.WriteTo.Console()
.CreateLogger();
Note: The property names are treated case-insensitive. If you specify
When you log any message with an email
property it will be masked:
logger.Information("This is a sensitive {Email}", "this doesn't match the regex at all");
the rendered log message comes out as: "This is a sensitive ***MASKED***"
Never mask a property
It may be that you never want to mask the value of a property regardless of whether it matches a pattern for any of the masking operators. In that case you can specify that the property is never masked:
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMasking(options => options.ExcludeProperties.Add("email"))
.WriteTo.Console()
.CreateLogger();
Note: The property names are treated case-insensitive. If you specify
When you log any message with an email
property it will not be masked:
logger.Information("This is a sensitive {Email}", "user@example.com");
the rendered log message comes out as: "This is a sensitive user@example.com"
Extending to additional use cases
Depending on the type of masking operation you want to perform, the RegexMaskingOperator
base class is most likely your best starting point. It provides a number of extension points:
Method | Purpose |
---|---|
ShouldMaskInput | Indicate whether the operator should continue with masking the input |
PreprocessInput | Perform any operations on the input value before masking the input |
PreprocessMask | Perform any operations on the mask before masking the matched value |
ShouldMaskMatch | Indicate whether the operator should continue with masking the matched value from the input |
To implement your own masking operator, inherit from RegexMaskingOperator
, supply the regex through the base constructor and where necessary override any of the above extension points.
Then, when configuring your logger, pass your new encricher in the collection of masking operators:
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMasking(options => {
// Add your masking operator:
options.MaskingOperators.Add(new YourMaskingOperator());
})
.WriteTo.Console()
.CreateLogger();
JSON configuration
If you are configuring your logger through appsettings.json
, you can configure the enricher too. You will have to add a Using
section if it doesn't exist already and include the Serilog.Enrichers.Sensitive
assembly name there, otherwise configuration will silently fail.
{
"Serilog": {
"Using": [
"Serilog.Enrichers.Sensitive"
],
"Enrich": [
{
"Name": "WithSensitiveDataMasking",
"Args": {
"options": {
"MaskValue": "CUSTOM_MASK_FROM_JSON",
"ExcludeProperties": [
"email"
],
"Mode": "Globally"
}
}
}
]
}
}
Note that options
is the argument name of the WithSensitiveDataMasking
extension method and must match exactly.
Masking operators
To configure masking operators you will need to specify the fully qualified name of the masking operator type. For example: MyApplication.Logging.Serilog.MyCustomMaskingOperator, MyAppliation.Logging
for the type MyCustomMaskingOperator
in the MyApplication.Logging
assembly.
An example config file:
{
"Serilog": {
"Using": [
"Serilog.Enrichers.Sensitive"
],
"Enrich": [
{
"Name": "WithSensitiveDataMasking",
"Args": {
"options": {
"MaskValue": "CUSTOM_MASK_FROM_JSON",
"Operators": [ "MyApplication.Logging.Serilog.MyCustomMaskingOperator, MyAppliation.Logging" ]
}
}
}
]
}
}
Warning: Contrary to what you might expect, for JSON configuration
Operators
should be used instead ofMaskingOperators
.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages (9)
Showing the top 5 NuGet packages that depend on Serilog.Enrichers.Sensitive:
Package | Downloads |
---|---|
Org.Eclipse.TractusX.Portal.Backend.Framework.Logging
The Catena-X Portal Backend Framework library is a versatile .NET library that provides a set of powerful tools and utilities for common development tasks. This package simplifies various aspects of your application, including database interactions, asynchronous programming, file I/O, LINQ operations, logging, and database seeding. |
|
Tingle.Extensions.Serilog
Extensions for working with Serilog. Including easier registration when working with different host setups, and general basics. |
|
fgli-sharedlibrary
Package Description |
|
Carbon.Serilog
Package Description |
|
NKZSoft.Service.Configuration.Logger
Provides the configuration for Serilog |
GitHub repositories (3)
Showing the top 3 popular GitHub repositories that depend on Serilog.Enrichers.Sensitive:
Repository | Stars |
---|---|
goatcorp/FFXIVQuickLauncher
Custom launcher for FFXIV
|
|
sunnamed434/BitMono
Obfuscator for .NET and Mono, with a customizable engine for building your own obfuscators.
|
|
PlexRipper/PlexRipper
The best cross-platform Plex media downloader there is! In active development and feedback is very welcome!
|
Version | Downloads | Last updated |
---|---|---|
1.7.3 | 2,903,377 | 8/4/2023 |
1.7.2 | 1,032,206 | 3/4/2023 |
1.7.1 | 187,562 | 2/3/2023 |
1.7.0 | 341,360 | 1/23/2023 |
1.6.0 | 352 | 1/23/2023 |
1.5.1 | 895,471 | 10/20/2022 |
1.5.0 | 2,278 | 10/19/2022 |
1.4.0 | 38,134 | 10/11/2022 |
1.3.0 | 18,655 | 10/2/2022 |
1.2.0 | 58,722 | 9/10/2022 |
1.1.0 | 1,021 | 9/9/2022 |
1.0.0 | 1,511,358 | 5/31/2021 |
0.4.0 | 105,619 | 10/12/2020 |
0.3.0 | 620 | 10/12/2020 |
0.2.0 | 678 | 3/10/2020 |
0.1.2 | 682 | 3/3/2020 |
0.1.1 | 643 | 3/3/2020 |
0.1.0 | 3,581 | 3/2/2020 |