如何使用log4net在长字符串的序列化JSON中屏蔽敏感值
日志敏感信息屏蔽方案(无需修改调用代码)
针对你在ASP.NET Core项目中遇到的日志脱敏需求,以下是几种无需改动原有调用代码的可行方案:
方案1:基于log4net自定义消息转换器(推荐)
从你使用LogManager.GetLogger的代码来看,项目应该用的是log4net日志框架。我们可以通过自定义消息转换器,在日志输出环节自动替换敏感内容:
步骤1:实现自定义转换器类
public class SensitiveDataMaskingConverter : PatternConverter { protected override void Convert(TextWriter writer, object state) { var loggingEvent = state as LoggingEvent; if (loggingEvent == null) { base.Convert(writer, state); return; } // 获取原始日志消息 var rawMessage = loggingEvent.RenderedMessage; // 正则匹配JSON格式的pwd字段,替换值为***(忽略大小写) var maskedMessage = Regex.Replace( rawMessage, @"(""pwd""|pwd):""[^""]+""", "$1:\"***\"", RegexOptions.IgnoreCase ); writer.Write(maskedMessage); } }
步骤2:修改log4net配置文件
在配置中注册转换器,并替换原有消息输出为脱敏后的内容:
<log4net> <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <!-- 注册自定义转换器,命名为mask --> <converter> <name value="mask" /> <type value="你的命名空间.SensitiveDataMaskingConverter" /> </converter> <!-- 用%mask替代%message输出脱敏后的日志 --> <conversionPattern value="%date [%thread] %-5level %logger - %mask%newline" /> </layout> </appender> <!-- 其他appender和root配置保持不变 --> </log4net>
这个方案只作用于日志输出环节,完全不影响业务代码的序列化逻辑,也不需要修改原有调用代码。
方案2:全局配置JsonConvert脱敏(谨慎使用)
如果希望从序列化源头处理,但要注意此方案会影响所有使用JsonConvert的场景:
步骤1:实现敏感字段转换器
public class SensitiveStringConverter : JsonConverter<string> { // 可扩展需要脱敏的字段列表 private readonly HashSet<string> _sensitiveFields = new() { "pwd", "password", "secret" }; public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer) { var currentField = writer.Path.Split('.').LastOrDefault(); if (_sensitiveFields.Contains(currentField?.ToLower())) { writer.WriteValue("***"); } else { writer.WriteValue(value); } } public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer) { return reader.Value?.ToString(); } }
步骤2:全局注册转换器
在项目启动时(比如Program.cs)添加:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = new List<JsonConverter> { new SensitiveStringConverter() } };
方案3:基于Microsoft.Extensions.Logging的日志过滤器
如果项目集成了微软原生日志框架,可以通过自定义过滤器拦截并修改日志消息:
步骤1:实现过滤器和包装Logger
public class SensitiveDataMaskingFilter : ILoggerProvider { private readonly ILoggerProvider _innerProvider; public SensitiveDataMaskingFilter(ILoggerProvider innerProvider) { _innerProvider = innerProvider; } public ILogger CreateLogger(string categoryName) { var innerLogger = _innerProvider.CreateLogger(categoryName); return new MaskingLogger(innerLogger); } public void Dispose() => _innerProvider.Dispose(); private class MaskingLogger : ILogger { private readonly ILogger _innerLogger; public MaskingLogger(ILogger innerLogger) { _innerLogger = innerLogger; } public IDisposable BeginScope<TState>(TState state) => _innerLogger.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => _innerLogger.IsEnabled(logLevel); public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { var originalMsg = formatter(state, exception); var maskedMsg = Regex.Replace( originalMsg, @"(""pwd""|pwd):""[^""]+""", "$1:\"***\"", RegexOptions.IgnoreCase ); _innerLogger.Log(logLevel, eventId, state, exception, (s, e) => maskedMsg); } } }
步骤2:注册过滤器
在Program.cs中添加:
builder.Logging.AddProvider(new SensitiveDataMaskingFilter(new ConsoleLoggerProvider((_, __) => true, true)));
内容的提问来源于stack exchange,提问作者BigThinker
相关产品推荐
相关产品推荐

