Slin.MaskEngine 1.0.4

Suggested Alternatives

Slin.Masking

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package Slin.MaskEngine --version 1.0.4
NuGet\Install-Package Slin.MaskEngine -Version 1.0.4
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Slin.MaskEngine" Version="1.0.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Slin.MaskEngine --version 1.0.4
#r "nuget: Slin.MaskEngine, 1.0.4"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Slin.MaskEngine as a Cake Addin
#addin nuget:?package=Slin.MaskEngine&version=1.0.4

// Install Slin.MaskEngine as a Cake Tool
#tool nuget:?package=Slin.MaskEngine&version=1.0.4

Slin.MaskEngine

This is a library developed in C# and target for .NET Framework and .NET Core. It allow developer to mask a string by given format or given profile.

Background

In services, there are a lot calls from one to another, or 3rd party services. We need to trace the request traffic, it's commonly RESTful API calls, WCF calls. We need to get it logged into logging system, that would be helpful for aduit or troubleshooting. However, there are some sensitive information on production, we should not get it logged as plain text. So we need to mask the sensitive values. That is the main purpurse of this project that to provide a flexiable MaskEngine to mask the sensitive values for the payload in traffics.

Introduction

Mask Format

The built in mask format would be like L4*6R4, which means keep 4 of left and 4 of right part of the input string and mask the middle part with 6 *.

Examples:

Input String Mask Format Mask Result
12345678901234 L4*6R4 1234******1234
1234567890 L4*6?R4 1234**7890
Shawn L2*4R0 Sh****

Here are some exaples: For bank account number, which is 16 digits usually, we'd like to use L4*8R4; For FirstName or LastName, we'd like to use L2*4R0

Usage Introduction

It's really simple that in most case you only need to:

  • Initialized a global/singleton MaskEngine instance
  • Define the mask profile that which kinds of names should be masked and masked in which way by adding MaskAttribute to your fields/properties.
  • Call APIs to mask the string ** Normaully, you can pass the request body, response body of Json or Xml/Soap directly to MaskEngine.MaskObjectString, which will mask everything on the fly as long as you get MaskProfile setup.

NOTE A global instance/singleton instance of MaskEngine is suggested if the Maskconfiguration is same.

define and enable Mask Profile

Mask profile can be defined:

  1. by a class, which got fields/properties with MaskAttribute applied with corresponding mask setting

    public class LogKeys
    {
        [MaskAttribute(MaskFormat = "L4*8R4", FilterPattern = "\\d{16}")]
        public string AccountReference = "AccountReference";

        [MaskAttribute(MaskFormat = "*14")]
        public string Pin = "pin";

        [MaskAttribute(MaskFormat = "L4*8R4")]
        public string AccountNumber = "AccountNumber";

        [MaskAttribute(MaskFormat = "L0*6R3")]
        public string Ssn = "SSN";
        [MaskAttribute(MaskFormat = "L0*6R3")]
        public string SocialSecurityNumber = "SocialSecurityNumber";
        
        public string ClientIp = "ClientIp";
        public string ServerName = "ServerName";
        [MaskAttribute(MaskFormat = "L2*8?R0")]
        public string FirstName = "FirstName";
        [MaskAttribute(MaskFormat = "L2*8?R0")]
        public string LastName = "LastName";
        [MaskAttribute(MaskFormat = "L3*4R4")]
        public string PhoneNumber = "LastName";

        //TODO may got different formats
        [MaskAttribute(Replacement = "1970-01-01T00:00:00")]
        public string DateOfBirth = "DateOfBirth";

        [MaskAttribute(MaskFormat = "*6")]
        public string Password = "Password";
    }
  1. by setting MaskProfileFactory
            maskEngine.Configuration.MaskProfileFactory = () =>
            {
                return new Dictionary<string, MaskAttribute>
                {
                    ["mykey1"] = new MaskAttribute() { MaskFormat = "L4$4?R4" },
                    ["mykey1"] = new MaskAttribute() { MaskFormat = "L0#4?R0" },
                };
            };
            maskEngine.UseProfile<LogKeys>().FinalizeConfiguration();

NOTE: a) the profile is case-insensitive! b) after set MaskEngineConfiguration.MaskProfileFactory, you need to explictly call FinalizeConfiguration() to finalize the configuration. c) If Mask Profile got set UseProfile<T>() alreay and you also use MaskEngineConfiguration.MaskProfileFactory, duplicated mask profile item would be ignored inside FinalizeConfiguration().

  1. Special cases We usually like to use key-value-pair list to passing options/parameters, and some of them may got sensitive information in it. by default, name with "key" and value with name of "value" (case in-sensitive) will be processed. For example, key with name like "AccountNumber" will be masked once your mask profile get it set. Here, I got it enhanced that allow adding customized key-value name. Below is the example:
            maskEngine.Configuration.KeyNameValueNameList
                .Add(new KeyValPair("customkey".ToLower(), "customvalue".ToLower()));

Mask string, serialized Json or XML document

In MaskEngine it provided following APIs:

BUT, actually, I think MaskObjectString is the most powerful method that you can benifit from it.

Examples

Source code

    public interface IMaskEngine
    {
        IMaskEngineConfiguration Configuration { get; }

        /// <summary>
        /// should be called after customized configuration got set,
        /// not been called if got custom configuration, some function may not working well.
        /// </summary>
        /// <returns></returns>
        IMaskEngine FinalizeConfiguration();

        bool IsNameInMaskList(string name);

        string Mask(string name, string value);

        string MaskObjectString(string serializedString);

        string MaskUrl(Uri uri, bool processSegements = true);
        
        /// <summary>
        /// Use a class with properties/fields got MaskAttribute setting
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        IMaskEngine UseProfile<T>() where T : class;
    }

Example of code:

static IMaskEngine MyMaskEngine;
static void Main(){
        var maskEngine = new MaskEngine();
        #region custom configurations
        maskEngine.Configuration.KeyNameValueNameList
            .Add(new KeyValPair("customkey".ToLower(), "customvalue".ToLower()));
        maskEngine.Configuration.JsonStringOrXmlStringContentKeyNameChecker = (name, context) =>
        {
            return ",response_body,response_content,simple_json_str_bad,simple_xml_str_bad,simple_xml_kvp_str_bad,"
            .Contains("," + name.ToLower() + ",");
        };
        maskEngine.Configuration.MaskProfileFactory = () =>
        {
            return new Dictionary<string, MaskAttribute>
            {
                ["mykey1"] = new MaskAttribute() { MaskFormat = "L4$4?R4" },
                ["mykey1"] = new MaskAttribute() { MaskFormat = "L0#4?R0" },
            };
        };
        #endregion
        maskEngine.UseProfile<LogKeys>().FinalizeConfiguration();
        
        MyMaskEngine = maskEngine;
        
        //samples
        SimpleStringSample();
}

void SimpleStringSample(){
     var masked = MyMaskEngine("firstname", "Shawn");
     Console.WriteLine(masked);  //got "Sh***"
}
void JsonStringSample(){
     var json = "{\"firstname\":\"Shawn\",\"lastname\":\"lin\", \"options\":[{\"key\":\"ssn\",\"value\":\"123456789\"}]}";
     var masked = MyMaskEngine.MaskObjectString(json);
}

void XmlStringSample(){

}

public class LogKeys{
    //... check section # define and enable Mask Profile
}

Others

For more details, please check the properties of MaskEngineConfiguration. And please email to me if you have any questions and suggestions.

Thanks you!

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated

# 1.0.4 Fix a critial issue in MaskAttribute when FilterPattern got applied; add "new()" constraint for T for MaskEngine.UseProfile