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.
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 protected]
.
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 protected]
will be:
Request start GET /api/users/?email=***MASKED***
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).
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}", "[email protected]");
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***"
}
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}", "[email protected]");
}
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.
Extending this enricher is a fairly straight forward process.
- Create your new class and inherit from the RegexMaskingOperator base class
- Pass your regex pattern to the base constructor
- To control if the regex replacement should even take place, override ShouldMaskInput, returning
true
if the mask should be applied, andfalse
if it should not. - Override PreprocessInput if your use case requires adjusting the input string before the regex match is applied.
- Override PreprocessMask if your use case requires adjusting the mask that is applied (for instance, if your regex includes named groups). See the CreditCardMaskingOperator for an example.
- When configuring your logger, pass your new encricher in the collection of masking operators
var logger = new LoggerConfiguration()
.Enrich.WithSensitiveDataMasking(MaskingMode.InArea, new IMaskingOperator[]
{
new EmailAddressMaskingOperator(),
new IbanMaskingOperator(),
new CreditCardMaskingOperator(false),
new YourMaskingOperator()
})
.WriteTo.Console()
.CreateLogger();