5.7.5 日志脱敏与敏感信息保护
日志是脚本可观测性的核心,但也常成为敏感信息泄露的入口。本节聚焦在 Shell 脚本中对日志内容的脱敏与保护,确保在排错、审计的同时满足合规与安全要求,并给出可执行示例、排错与练习。
1. 识别敏感信息与风险边界#
常见敏感信息包括:
- 账号与密码:数据库/中间件账号、API Key、Token、证书私钥
- 个人信息:手机号、邮箱、身份证、姓名
- 业务密钥:支付密钥、内部服务鉴权串
- 系统信息:内网地址、主机名、版本细节
风险边界应明确:
- 日志可被哪些人访问
- 日志存储周期与归档位置
- 是否传输到外部系统(如 ELK、SLS、SIEM)
原理草图(脱敏与安全日志链路):
2. 日志脱敏基本策略#
- 最小化日志原则:只记录必要信息,不记录敏感字段
- 部分保留:仅保留必要片段(如手机号前3后4)
- 哈希替代:用于审计关联的字段用哈希表示
- 替换标记:明确标识已脱敏字段
[REDACTED]
示例(仅展示必要字段):
- user=tom token=***
- phone=138****1234
- apikey=sha256:9c1d...
3. Shell 中的脱敏实现方式#
3.1 使用 sed 进行正则脱敏#
log='user=tom password=Passw0rd token=abcd1234 phone=13812341234'
echo "$log" | sed -E 's/(password|passwd|token)=([^ ]+)/\1=*** /g' \
| sed -E 's/(phone=)([0-9]{3})[0-9]{4}([0-9]{4})/\1\2****\3/'
命令解释:
- sed -E 启用扩展正则
- 第一条规则将 password/token 的值替换为 ***
- 第二条规则保留手机号前3后4
3.2 使用 awk 按字段脱敏#
log='user=tom token=abcd1234 ip=10.0.0.1'
echo "$log" | awk '{
for(i=1;i<=NF;i++){
if($i ~ /^token=/){ sub(/=.*/, "=***", $i) }
}
print
}'
命令解释:
- NF 字段数量
- sub 仅替换当前字段
3.3 使用参数替换快速屏蔽#
secret="ABCD1234XYZ"
masked="${secret:0:2}****${secret: -2}"
echo "token=$masked"
命令解释:
- ${secret:0:2} 取前2位
- ${secret: -2} 取后2位
3.4 统一脱敏函数(推荐)#
保存脚本:/opt/scripts/lib/log_secure.sh
#!/usr/bin/env bash
mask_kv() {
echo "$1" | sed -E \
-e 's/(password|passwd|token|apikey)=([^ ]+)/\1=*** /g' \
-e 's/(phone=)([0-9]{3})[0-9]{4}([0-9]{4})/\1\2****\3/'
}
log_info() { echo "$(date +%F\ %T) [INFO] $(mask_kv "$*")"; }
调用示例:
source /opt/scripts/lib/log_secure.sh
log_info "user=tom token=abcd1234 phone=13812341234"
预期效果:
2024-05-01 12:00:00 [INFO] user=tom token=*** phone=138****1234
4. 输出控制与日志级别#
- 仅在 debug 环境输出详细日志
- 通过环境变量控制日志级别:
LOG_LEVEL=${LOG_LEVEL:-INFO}
log_debug(){ [ "$LOG_LEVEL" = "DEBUG" ] && echo "$(date +%F\ %T) [DEBUG] $*"; }
- 禁止在生产环境输出
set -x中的参数(可能泄露)
示例:安全日志输出骨架
#!/usr/bin/env bash
source /opt/scripts/lib/log_secure.sh
LOG_LEVEL=${LOG_LEVEL:-INFO}
log_debug "request=full_body token=abcd1234"
log_info "user=tom action=login token=abcd1234"
5. 保护敏感日志的存储与传输#
- 文件权限:日志文件权限设置为
600 - 目录隔离:敏感日志单独目录隔离
- 日志轮转:防止长期暴露
- 传输加密:推送到集中日志时使用 HTTPS/TLS
- 审计访问:记录谁访问/下载了日志
5.1 安全日志目录与权限#
sudo install -d -m 700 /var/log/app_secure
sudo install -m 600 /dev/null /var/log/app_secure/app.log
命令解释:
- -d 创建目录
- -m 指定权限
5.2 安装并配置 logrotate(示例)#
安装:
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y logrotate
# RHEL/CentOS
sudo yum install -y logrotate
配置文件:/etc/logrotate.d/app_secure
/var/log/app_secure/app.log {
daily
rotate 7
missingok
compress
delaycompress
notifempty
create 600 root root
}
手动测试:
sudo logrotate -vf /etc/logrotate.d/app_secure
预期效果:生成 app.log.1 并压缩历史日志。
5.3 传输加密示例(curl + HTTPS)#
curl -sS -X POST https://log.example.com/ingest \
-H "Content-Type: text/plain" \
--data-binary @/var/log/app_secure/app.log
命令解释:
- --data-binary 保持内容原样
- 使用 HTTPS 保护传输
6. 常见误区与规避#
- 直接输出命令参数:如
mysqldump -pPASSWORD - 调试时开启 set -x:会输出所有变量与命令
- 把密钥写入日志:排错完忘记清理
- 把完整响应体打印:可能包含 token/PII
正确做法:
- 使用环境变量或文件传参
- 调试仅本地、短期、脱敏后再提交
示例(安全传参):
# 不在命令行暴露密码
export MYSQL_PWD='StrongPass'
mysqldump -h 127.0.0.1 -uroot dbname > /tmp/db.sql
unset MYSQL_PWD
7. 排错指南#
7.1 脱敏规则未生效#
排查命令:
log='password=123 token=abc'
echo "$log" | sed -E 's/(password|token)=([^ ]+)/\1=*** /g'
检查点:
- 是否启用了 -E
- 是否有多余空格或字段格式不一致
7.2 日志权限被拒绝#
ls -l /var/log/app_secure/app.log
id
检查点:
- 文件权限是否为 600
- 当前用户是否为 root 或日志所属用户
7.3 logrotate 不轮转#
sudo logrotate -d /etc/logrotate.d/app_secure
检查点:
- 配置路径是否正确
- create 权限是否匹配
8. 练习#
- 编写
mask_kv,新增对email=的脱敏规则(仅保留域名)。 - 写一个脚本
secure_log_demo.sh:接收一行输入,脱敏后写入/var/log/app_secure/app.log。 - 配置
logrotate,将保留周期改为 14 天,并验证轮转效果。 - 将
LOG_LEVEL=DEBUG时输出详细日志,但保证脱敏依然生效。