信息安全无小事,手把手教你日志脱敏

2023-11-17

场景

我们开发的程序迟早有一天都会上线到生产环境运行,但是没有人能保证自己的代码100%不出BUG(别抬扛,真没BUG是代码写的少)

当我们线上出BUG之后,最常见的定位问题方法就是排查日志文件,所以我们一般都会在开发程序时,在适当的位置输出一些日志信息。

并且有一些日志并不是只打印一些业务字段,可能会将整个对象输出到日志中。比如这样:

log.info("客户信息:{}",JSON.toJSONString(customer));

从代码的角度来说,不太严格的话,如果这个customer对象不是特别大的话,倒也没有多大的问题。

但是咱们换个角度,从信息安全的角度来说,这会直接将用户的所有信息都打印在日志中。

假设某一天,开发小哥或者运维小哥因为某些不太建议的操作,恶意从日志中获取用户的信息,比如用户的手机号,邮箱,身份证号,家庭住址。。。。如果你们公司是一家金融类公司,直接获取到一些富豪客户的信息,然后去做一些非法交易,后果很严重。

(警告 :这是反面教材,万万不可尝试)

img

所以我们要怎么避免这种问题的发生呢?

主要从以下几个方面解决:

  • 避免在代码中将敏感信息直接输出
  • 通过日志组件进行脱敏
  • 其他我也不知道的方法。。

在代码中避免的难度相对要更大一点,在一个项目的整个开发周期中很难让所有人都能完全按照规范来执行,所以我们还是要用第二种方式来进行兜底。

接下来的内容主要和大家讲解一下如何通过日志组件进行脱敏。

在Java项目中使用的日志组件一般都会选择Logback或者Log4j,前段时间log4j漏洞风波沸沸扬扬,我们pass它,使用logback来做。

Logback

Logback是 Java 社区中使用最广泛的日志记录框架之一。它是其 Log4j 的替代品,比 Log4j 更快,并提供了更多的配置选项,归档日志文件更灵活。

数据脱敏

在我们的系统中多多少少都会有敏感信息,比如身份证号,家庭住址,银行卡号,手机号,邮箱等等,我们需要在记录日志时将这些敏感信息进行脱敏。

假设我们会有如下用户信息日志输出:

{
    "user_id":"123456",
    "address":"朝阳区百子湾街道某小区1单元101",
    "city":"北京市",
    "Country":"中国",
    "mobile":"18888888888",
    "email":"heiz123@xxx.com"
}

在这个用户信息中,用户的地址,电话,手机,邮箱信息都是比较敏感的,我们需要进行脱敏。

要实现这个功能,我们可以给Logback配置上脱敏规则,将脱敏规则添加到Logback的appender中。我们需要自定义一个Logback的PatternLayout

自定义PatternLayout

我们自定义PatternLayout的目的是为了将脱敏规则添加到logback配置中的所有appender中。

package com.heiz123.log.layout;

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

/**
 * @author yuriy.lu
 * @ClassName MaskingPatternLayout
 * @Description
 * @date 2022/1/26
 **/
public class MaskingPatternLayout extends PatternLayout {

    private Pattern multilinePattern;
    private final List<String> maskPatterns = new ArrayList<>();

    public void addMaskPattern(String maskPattern) {
        maskPatterns.add(maskPattern);
        multilinePattern = Pattern.compile(String.join("|", maskPatterns), Pattern.MULTILINE);
    }

    @Override
    public String doLayout(ILoggingEvent event) {
        return maskMessage(super.doLayout(event));
    }

    private String maskMessage(String message) {
        if (multilinePattern == null) {
            return message;
        }
        StringBuilder sb = new StringBuilder(message);
        // 使用正则匹配符合脱敏要求的数据
        Matcher matcher = multilinePattern.matcher(sb);
        while (matcher.find()) {
            IntStream.rangeClosed(1, matcher.groupCount()).forEach(group -> {
                if (matcher.group(group) != null) {
                    // 将符合格式的数据用*替换
                    IntStream.range(matcher.start(group), matcher.end(group)).forEach(i -> sb.setCharAt(i, '*'));
                }
            });
        }
        return sb.toString();
    }
}

然后将我们自定义的MaskingPatternLayout配置在Appender中:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="com.heiz123.log.layout.MaskingPatternLayout"> <!-- 自定义layout -->
            <maskPattern>\"address\"\s*:\s*\"(.*?)\"</maskPattern> <!--json地址格式 -->
            <maskPattern>((1\d{2})\d{8})</maskPattern> <!-- 手机号格式 -->
            <maskPattern>(\w+@\w+\.\w+)</maskPattern> <!-- 邮箱格式 -->
            <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
        </layout>
    </encoder>
</appender>

然后我们来测试一下打印结果,使用如下代码模拟用户数据输出:

private static void testLog() {
    Map<String, String> user = new HashMap<>();
    user.put("user_id", "123456");
    user.put("mobile", "18888888888");
    user.put("address", "朝阳区百子湾街道某小区1单元101");
    user.put("city", "北京市");
    user.put("country", "中国");
    user.put("email", "heiz123@163.com");
    log.info("customer info: {}", JSON.toJSONString(user));
}

执行后输出结果如下:

com.heiz123.study.StudyApplication - customer info: {"country":"中国","address":"*****************","user_id":"123456","city":"北京市","mobile":"***********","email":"***************"}

嗯,达到了数据脱敏的目的。并且我们可以在配置文件中添加不同的正则表达式,对不同格式的信息进行脱敏。

实现原理

俗话说要知其然,知其所以然。

为什么在Appender中添加一个自定义Layout就可以做到脱敏呢?我通过阅读源码,给他家整理了一个Logback日志输出的流程图,方便大家理解。

在我们调用log.debug()或者log.info()以及其他级别的日志方法时,会按照上图中的流程执行。

红色字体部分的方法,就会调用到Encoder中的layoutdoLayout(Event),也就是我们配置文件中配置的自定义Layout

最后

以上就是本期的所有内容,主要跟大家讲解如何通过自定义PatternLayout,对logback输出的敏感日志进行脱敏,防止数据泄露。

如果对你有所帮助,希望能给小黑点个赞,就是对我最大的鼓励啦。

我是小黑,一名在互联网“苟且”的程序员

流水不争先,贵在滔滔不绝


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

信息安全无小事,手把手教你日志脱敏 的相关文章

  • NoInitialContextException:heroku 战争部署

    我一直在开发一个 J2EE 项目 并且在其中使用连接池 也通过部署在 heroku 上的数据库进行访问 我使用以下代码来设置 Connection 对象 Context initContext new InitialContext Cont
  • 使用 WebDriver 单击新打开的选项卡中的链接

    有人可以在这种情况下帮助我吗 场景是 有一个网页 我仅在新选项卡中打开所有指定的链接 现在我尝试单击新打开的选项卡中的任何一个链接 在下面尝试过 但它仅单击主 第一个选项卡中的一个链接 而不是在新选项卡中 new Actions drive
  • Oracle Java 教程 - 回答问题时可能出现错误

    我是 Java 新手 正在阅读 Oracle 教程 每个部分之后都有问题和答案 我不明白一个答案中的一句话 见下面的粗体线 来源是https docs oracle com javase tutorial java javaOO QandE
  • 从 MS Access 中提取 OLE 对象(Word 文档)

    我有一个 Microsoft Access 数据库 其中包含一个包含 Microsoft Word 文档的 OLE 对象字段 我试图找到代码来检索保存在 OLE 对象中的文件 以便用户可以从我的 JavaFx 应用程序中的按钮下载它 但没有
  • tomcat 7.0.50 java websocket 实现给出 404 错误

    我正在尝试使用 Java Websocket API 1 0 JSR 356 中指定的带注释端点在 tomcat 7 0 50 上实现 websocket 以下是我如何对其进行编码的简要步骤 1 使用 ServerEndpoint注解编写w
  • 为什么 MOVE CURSOR 在 OS X Mountain Lion 上不显示?

    我正在做一个项目 想看看 Swing 提供的每个光标是什么样子的 public class Test public static void main String args JFrame frame new JFrame frame set
  • Android蓝牙java.io.IOException:bt套接字已关闭,读取返回:-1

    我正在尝试编写一个代码 仅连接到运行 Android 5 0 KitKat 的设备上的 目前 唯一配对的设备 无论我尝试了多少方法 我仍然会收到此错误 这是我尝试过的最后一个代码 它似乎完成了我看到人们报告为成功的所有事情 有人能指出我做错
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • 如何删除日期对象的亚秒部分

    当 SQL 数据类型为时间戳时 java util Date 存储为 2010 09 03 15 33 22 246 如何在存储记录之前将亚秒设置为零 例如 在本例中为 246 最简单的方法是这样的 long time date getTi
  • Java、Spring:使用 Mockito 测试 DAO 的 DataAccessException

    我正在尝试增加测试覆盖率 所以我想知道 您将如何测试 DAO 中抛出的 DataAccessExceptions 例如在一个简单的 findAll 方法中 该方法仅返回数据源中的所有数据 就我而言 我使用 Spring JdbcTempla
  • Spring Data JPA:查询如何返回非实体对象或对象列表?

    我在我的项目中使用 Spring Data JPA 我正在演奏数百万张唱片 我有一个要求 我必须获取各种表的数据并构建一个对象 然后将其绘制在 UI 上 现在如何实现我的 Spring 数据存储库 我读到它可以通过命名本机查询来实现 如果指
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • JAVA中遍历JSON数据

    我是 JSON 新手 我使用 HTTPUrlConnections 并在 JAVA 程序中获得一些响应 响应数据将类似于 data id 1 userId 1 name ABC modified 2014 12 04 created 201
  • 避免 Java 中的重复导入:继承导入?

    有没有办法 继承 导入 Example 常见枚举 public enum Constant ONE TWO THREE 使用此枚举的基类 public class Base protected void register Constant
  • 如何从 Ant 启动聚合 jetty-server JAR?

    背景 免责声明 I have veryJava 经验很少 我们之前在 Ant 构建期间使用了 Jetty 6 的包装版本来处理按需静态内容 JS CSS 图像 HTML 因此我们可以使用 PhantomJS 针对 HTTP 托管环境运行单元
  • 禁用 Android 菜单组

    我尝试使用以下代码禁用菜单组 但它不起作用 菜单项仍然启用 你能告诉我出了什么问题吗 资源 菜单 menu xml menu menu
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • ECDH使用Android KeyStore生成私钥

    我正在尝试使用 Android KeyStore Provider 生成的私有文件在 Android 中实现 ECDH public byte ecdh PublicKey otherPubKey throws Exception try
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐

  • 批量给多台Android手机安装APK脚本

    问题场景 测试让开发给4台手机安装测试版的APK 现实跑4次程序 于是该程序说 要是有个一次性安装多台手机APK的方法就好了 于是该脚本就出现了 并且还可以安装多个apk 以上是2个apk同时给2台设备安装 一键即可 把需要安装的apk放到
  • 百度AI接口测试案列一:车牌识别

    1 打开百度AI网站 百度AI网站 2 登录百度账号 进入控制台 选择文字识别服务 如图 3 点击立即使用 然后创建应用 之后输入应用名称 描述 随便写 并选择应用类型 之后点击 立即创建 按钮 创建完毕 点击 返回应用列表 如下图 注 A
  • linux删除文件_Linux中如何删除常用方式无法删除的文件

    前言 我们都知道 在linux删除一个文件可以使用rm命令 但是有一些特殊名称的文件使用普通的rm方式却没法删除 本文介绍linux中删除特殊名称文件的多种方式 linux文件命名规则 在介绍之前 简单说明一下linux中文件命名规则 文件
  • RegExp正则表达式-基本语法

    RegExp 百度云资料 密码 f89c 里面有详细的语法跟例子 希望对大家有帮助 课前补充 转义字符 多行字符串 字符串换行符 n RegExp作用 匹配特殊字符或有特殊搭配原则的字符的最佳选择 创建方式 直接量 推荐 new RegEx
  • Python 装饰器深入解析

    1 什么是装饰器 装饰器是给现有的模块增添新的小功能 可以对原函数进行功能扩展 而且还不需要修改原函数的内容 也不需要修改原函数的调用 1 1 装饰器的使用符合了面向对象编程的开放封闭原则 开放封闭原则主要体现在两个方面 对扩展开放 意味着
  • [LeetCode]4 两个有序数组的中位数

    Median of Two Sorted Arrays 两个有序数组的中位数 难度 hard There are two sorted arrays nums1 and nums2 of size m and n respectively
  • webstorm vue 项目卡顿现象 解决

    Settings editor File Types ignore files and folders 要忽略的文件添加 node modules 然后点击应用 在项目中点击node modules 右键 Mark Directory as
  • CMAKE 工具 之 add_executable,include_directories和 AUX_SOURCE_DIRECTORY

    在上一章里面 我们用cmake做了一个最简单的项目 这一节我们尝试一写比较常见的cmake配置 这次我们构建如下的目录结构 其中int plus h的代码如下 int int plus const int a const int b int
  • 【经验贴】新手项目经理如何接手并管好项目?

    最近有刷到这样一些求助帖 初入职场两三年的项目经理现在开始独立带项目 由于缺乏经验不知道从何下手 询问如何能快速接手并管好项目呢 这个话题也引起了大家的热议 今天就给大家分享一下一些实践经验 1 刚拿到项目时 应该做哪些准备 新接手项目时
  • Octave 计算数据 from 吴恩达的机器学习

    1 乘积 A C 2 点乘 A B 将矩阵A中的元素点乘B中的对应元素相乘 A 2 对矩阵A中的每一个元素平方 1 A 得到每一个元素的倒数 3 log A 对每个元素进行求对数运算 4 exp A 自然数e的幂次运算 就是以e为底 以这些
  • MySql8.0以上版本安装

    一 下载mysql8 0 1 官网地址 https www mysql com 2 进入下载页面 3 选择版本下载 二 安装mysql 1 配置环境变量 变量名 MYSQL HOME 变量值 mysql存放路径 例如 D mysql 8 0
  • postgresql 扩展pg_cron,pg_stat_statements安装配置

    一 概述 pg cron是基于cron的作业调度插件 语法与常规cron相同 但它可以直接从数据库执行PostgreSQL命令 pg stat statements模块提供一种方法追踪一个服务器所执行的所有 SQL 语句的执行统计信息 可以
  • 技术和商业角度刷脸支付都将成为未来趋势

    刷脸支付 我们作为消费者来说 最直观的感受就是我们的支付方式发生了变化 付钱更方便了 从最开始我们带着现金出门买东西 到后来二维码支付 一个手机扫遍天下 对于商家来说他不需要停下来手中在做的事情来收钱找零 而对于我们消费者来说也是非常的快捷
  • Python 内置数据类型 03----元组

    目 录 1 元组的简介 1 1 元组概念 1 2 元组创建方式 1 2 1 使用 直接创建 1 2 2 使用 tuple 函数创建 1 3 元组访问方式 2 处理元组的内置函数 2 1 len 函数 2 2 max 函数 2 3 min 函
  • 【编程测试题】数列还原

    数列还原 题目描述 牛牛的作业薄上有一个长度为 n 的排列 A 这个排列包含了从1到n的n个数 但是因为一些原因 其中有一些位置 不超过 10 个 看不清了 但是牛牛记得这个数列顺序对的数量是 k 顺序对是指满足 i lt j 且 A i
  • virtualbox网络常见问题,virtualbox linux 无法访问网络,virtual box 中 linux ping 不通,配置NAT ssh 无法连接

    问题1 在virtualbox 安装了 linux 发现无法访问网络 解决 不要去改 etc resolv conf 正确的做法是在virtual box配置NAT地址转发 补充一下 我发现mac每次加载虚拟机都要点开高级 然后点端口配置
  • python opencv数组转图片 并显示

    pred是数组类型 先转为8位 pred np array pred np uint8 cv2 imshow 123 pred cv2 waitKey 0
  • Basic Level 1025 反转链表 (25分)

    题目 给定一个常数 K 以及一个单链表 L 请编写程序将 L 中每 K 个结点反转 例如 给定 L 为 1 2 3 4 5 6 K 为 3 则输出应该为 3 2 1 6 5 4 如果 K 为 4 则输出应该为 4 3 2 1 5 6 即最后
  • vue项目 依赖打包 与 import和dependencies 的关系

    项目打包时 依赖与package json中的dependencies和devDependencies并无关 我曾这样认为了好久 原来他们之间的关系是这样的 项目打包的依赖来自于你import from xxx 如无特殊设置 import的
  • 信息安全无小事,手把手教你日志脱敏

    场景 我们开发的程序迟早有一天都会上线到生产环境运行 但是没有人能保证自己的代码100 不出BUG 别抬扛 真没BUG是代码写的少 当我们线上出BUG之后 最常见的定位问题方法就是排查日志文件 所以我们一般都会在开发程序时 在适当的位置输出