Files
dlp-io/docs/DLP_ENVIRONMENT_NOTES.md
T
p40000043244@byd.com 457e4eed3f docs: DLP 环境特征调研记录与判定/写入逻辑说明
- docs/DLP_ENVIRONMENT_NOTES.md: 白名单矩阵/密文样本/属性不可区分等实测结论与探索过程
- README: DLP 程序化特征与 is_encrypted/写入通道实现逻辑摘要
2026-07-31 18:32:14 +08:00

8.0 KiB
Raw Blame History

DLP 环境特征调研与检测/写入实现逻辑

本文记录在本机(启用透明加密 DLP 的 Windows)上对 tests/DLP加密文件.pptxtests/DLP解密文件.pptx 两个样本的实测结论、探索过程,以及 dlp_io 据此实现的 is_encrypted() 判定逻辑和未加密写入通道选择逻辑。所有结论都来自实测,不同 DLP 产品/策略可能不同,库的应对方式是运行时探测而非硬编码假设。

一、样本事实

两个样本文件内容相同(解密后 SHA-256 均为 968b5db1…d2947100),大小完全相同(2,466,572 字节)。加密文件在磁盘上存密文, 前 16 字节对比:

明文视图: 504b0304 0a000000 0000874e e2400000   (标准 ZIP/PPTX 头 "PK\x03\x04")
密文视图: 181b031a 1510197c 0a19 0e7c 6f726c5f   (流式加密, 相同明文 0x00 在不同偏移密文不同)

特征:同尺寸、全文流式加密、无附加文件头/尾、无静态 magic 可识别。

二、文件属性层面无法区分(重要结论)

对两个样本逐项对比,全部一致:

  • attrib:都只有 A 属性(无 EFS 的 E 属性等差异)
  • dir /r:均无附加数据流(ADS
  • 文件大小、时间戳:一致

结论:无法通过任何文件元数据判断加密状态,唯一可靠的判别特征是内容。 这正是 is_encrypted() 采用内容对比的原因。

三、进程白名单模型(实测矩阵)

DLP 透明加密按「进程身份」决定是否介入读写。用「读取加密样本看到什么」实测:

进程 父进程 读加密样本视图 结论
python.exe 任意(含非白名单 bash 明文 (PK 头) 身份白名单,不继承、不降级
cmd.exetype 任意 明文 白名单
powershell.exe 任意 明文 白名单(读透明)
certutil.exe bash / cmd 密文 非白名单, raw 视图
Git Bash msys 工具(head/sha256sum/cat bash 密文 非白名单
git.exehash-object bash 明文 白名单(两样本 blob hash 相同)

关键推论:

  1. helper 桥接设计成立:打包 EXE(非白名单)拉起 python.exe 子进程,python 按身份 仍是白名单,读到的就是明文——这是库读取链路的根基。
  2. cmd /c type 不能当密文通道:cmd 是白名单,读到的同样是明文。社区直觉「用 cmd 读原始内容」在本 DLP 上不成立。
  3. certutil 是本机可用的 raw 视图工具:但 DLP 拦截白名单进程直接拉起它 python → certutil 报 WinError 786),必须经 cmd /c certutil … 中转。
  4. cmd /c 中文路径坑:把整条命令作为单个字符串传参会触发 cmd 的引号剥离规则, 中文文件名丢失(ERROR_FILE_NOT_FOUND);用列表参数(subprocess 自动逐个加引号) 则中文路径正常。

写入侧实测:

写入方 落盘结果(raw 视图校验)
python.exe 直写(.bin / .pptx 后缀) 明文(本机策略不加密 python 写入)
powershell.exestdin 管道 → [IO.File] 明文
cmd /c more > f 破坏二进制0x00→CRLF、TAB→空格),不可用
cmd /c copy /b con f 挂起等待控制台输入,不可用
certutil -decode - f 不支持 stdin 输入,不可用
findstr ^ f raw 密文视图,但按行重新包装(0x0A→CRLF 注入),只能看头部不能还原内容

注意:白名单读透明 ≠ 写加密。本机 python/powershell 读透明但写入落盘明文; 「白名单进程写入会被加密」的策略在其他机器上仍可能存在——所以写入通道必须 运行时探测,不能假设。

四、探索过程(方法记录)

  1. 多通道哈希对比certutil -hashfile(非白名单视图)对两样本哈希不同 (33d3… vs 968b…),python 读取两样本哈希相同(968b…)——证明 DLP 生效、 python 白名单、certutil 非白名单,一条命令同时确认三件事。
  2. 头部字节对比head -c 64 | xxd(msys 工具,raw 视图)看到密文头,确认 同尺寸流加密、无附加头。
  3. 文件属性对比attrib / dir /r 无差异——排除元数据检测路线。
  4. 写入通道候选实验:逐一验证 more/copy con/certutil -decode/findstr 全部 有二进制安全性或可用性问题,最终 powershell [Console]::OpenStandardInput() 管道方案通过全字节(含 0x00/0x1A/0xFF)哈希校验。
  5. 误报纠正python → cmd /c type 一度显示明文,先怀疑「白名单继承」, 后用 bash → cmd /c type(仍是明文)和 bash → python(明文)交叉验证, 确认 python/cmd 均为身份白名单而非继承。

五、is_encrypted() 判定逻辑

判据:文件已加密 ⟺ 白名单视图 ≠ 非白名单(raw)视图。

难点:当前进程自身是否白名单是未知的(Python/pyd 是白名单,打包 EXE 不是), 单次对比存在歧义。dlp_io.is_encrypted(path) 用两阶段消歧:

h_raw    = certutil -hashfile(path)     # 非白名单 raw 视图(经 cmd /c 中转)
h_native = hashlib(当前进程读 path)

if h_raw != h_native:
    return True          # 视图不一致: 文件已加密, 且当前进程是白名单

# 歧义分支: 文件未加密, 或文件已加密但当前进程是非白名单 EXE
head_helper = helper(白名单 python)读前 64 KiB
head_native = 当前进程读前 64 KiB
return head_helper != head_native

三种运行环境全部正确:

环境 加密文件 未加密文件
Python / pyd(白名单) 阶段一即判定 True 阶段二两视图一致 → False
打包 EXE(非白名单) 阶段一相等(都看到密文)→ 阶段二 helper 明文头 ≠ 本地密文头 → True 阶段二一致 → False

代价:未加密文件需一次完整 certutil 哈希 + 一次本地完整读取 + helper 前 64 KiB 读取;大文件应缓存结果。库故意不引入「期望 magic 表」——内容对比与文件类型无关。

六、未加密写入通道选择逻辑

目标:任何环境下 dlp_io.open(path, "w"/"a"/"x") 落盘都是未加密文件。

首次写某后缀时:
  1. 环境变量 DLP_IO_WRITE_CHANNEL=direct|powershell → 强制, 跳过探测
  2. 直写探测: temp 目录写探针文件(同后缀, 含 0x00/0x1A/0xFF 等边界字节)
     → certutil raw 哈希 == 内容哈希 ?
     - 一致 → DIRECTEXE 环境恒真; 本机 python 也真)
     - certutil 不可用 → 视为无 DLP → DIRECT
  3. 否则 PowerShell 中转探测: 同 payload 经 stdin 管道由 powershell 子进程
     ([Console]::OpenStandardInput → [IO.File]::Open) 写盘 → 再校验 raw 哈希
     - 一致 → POWERSHELL
  4. 都失败 → raise DlpWriteError(绝不静默写出密文)
结果按后缀缓存(DLP 写策略常按文档类型区分)。

中转通道要点:字节只走 stdin 内存管道,不落地任何临时文件(白名单进程写的临时 文件本身可能被加密,会造成「密文套娃」);FileMode 映射 w→Createa→Appendx→CreateNewx 模式在通道选择前先做本地存在性检查,保证 FileExistsError 语义与原生一致。

已知边界:探测文件写在 temp 目录,若 DLP 策略按目录区分,探针结论可能与目标 目录不符——此时用 DLP_IO_WRITE_CHANNEL 显式指定。

七、相关已知问题

  • 保护区内 git push 必现 fatal: not a git repositoryDLP 拦截 push 进程 对 .git 的访问模式),解法见 .kimi-code/skills/git-push-dlp/robocopy 镜像 .git 到 TEMP 后从 stage 目录推送)。
  • 提交样本 fixture 时注意:本机 git.exe 是白名单视图,commit 会把加密样本按 明文存入仓库。测试用例已按环境自适应编写(依据本机 raw 视图与本地视图是否 一致判断期望),CI(无 DLP)与 DLP 开发机都能通过。