- is_encrypted(): certutil 原始哈希 + helper 视图对比, Python/pyd/EXE 三环境均可判定 - w/a/x 写入按后缀探测通道, 直写会被加密时自动切换 PowerShell stdin 中转, 保证落盘未加密 - 新增 WriteChannel/DlpWriteError 与 DLP_IO_WRITE_CHANNEL 强制通道开关 - tests: DLP 加解密样本 fixture 与 19 个结构化断言用例
This commit is contained in:
+42
-5
@@ -1,8 +1,8 @@
|
||||
# dlp-io
|
||||
|
||||
`dlp-io` 为 Windows DLP 透明加密环境提供接近 `io.open` 的 Python 文件 API。非白名单进程负责业务逻辑和写入;文件读取由已获 DLP 白名单授权的 Python helper 完成,再通过经过认证的 Windows Named Pipe 返回明文字节。
|
||||
`dlp-io` 为 Windows DLP 透明加密环境提供接近 `io.open` 的 Python 文件 API。非白名单进程负责业务逻辑;文件读取由已获 DLP 白名单授权的 Python helper 完成,再通过经过认证的 Windows Named Pipe 返回明文字节;文件写入通过通道探测保证落盘为未加密格式。另提供 `is_encrypted()`,在读取前判断文件是否处于 DLP 加密状态。
|
||||
|
||||
当前版本为 `dlp-io==0.1.1`,distribution 名是 `dlp-io`,import 名是 `dlp_io`。
|
||||
当前版本为 `dlp-io==0.2.0`,distribution 名是 `dlp-io`,import 名是 `dlp_io`。
|
||||
|
||||
## 安装
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
registry 已开放匿名下载,一条命令即可安装;pip 会自动选择最匹配的 wheel:Windows 上 CPython 3.10–3.14 会得到对应的 pyd wheel(整个库编译为单个 `.pyd`),其余环境得到纯 Python wheel。
|
||||
|
||||
```powershell
|
||||
py -m pip install --index-url https://gitea.docker.antior.cn/api/packages/antior/pypi/simple dlp-io==0.1.1
|
||||
py -m pip install --index-url https://gitea.docker.antior.cn/api/packages/antior/pypi/simple dlp-io==0.2.0
|
||||
```
|
||||
|
||||
Package 页面:<https://gitea.docker.antior.cn/antior/-/packages/pypi/dlp-io>
|
||||
@@ -78,14 +78,50 @@ dlp_io.shutdown()
|
||||
|
||||
模式路由规则:
|
||||
|
||||
- 路径型 `r`、`rt`、`rb`:通过 helper 读取。
|
||||
- 路径型 `w`、`a`、`x`:使用原生 `open` 写入。
|
||||
- 路径型 `r`、`rt`、`rb`:通过 helper 读取,始终返回明文。
|
||||
- 路径型 `w`、`a`、`x`:经过写入通道路由(见下文「未加密写入」),保证落盘为未加密文件。
|
||||
- 整数文件描述符或自定义 `opener`:使用原生 `open`。
|
||||
- 路径型 `+` 更新模式:显式抛出 `io.UnsupportedOperation`。
|
||||
- 路径读取配合 `closefd=False`:与标准 API 一样抛出 `ValueError`。
|
||||
- `rb` 配合 `buffering=0`:返回 raw stream;默认返回 buffered reader。
|
||||
- 文本模式的默认 encoding 与当前 Python `io.open` 一致;跨机器文件请显式传 `encoding="utf-8"`。
|
||||
|
||||
## 加密状态判断
|
||||
|
||||
`is_encrypted(path)` 在读取前判断文件是否处于 DLP 加密状态,返回 `bool`:
|
||||
|
||||
```python
|
||||
import dlp_io
|
||||
|
||||
if dlp_io.is_encrypted(r"D:\Protected\input.pptx"):
|
||||
# 已加密:当前进程若是打包的 EXE(非白名单),必须经 helper 中转读取
|
||||
with dlp_io.open(r"D:\Protected\input.pptx", "rb") as stream:
|
||||
data = stream.read()
|
||||
else:
|
||||
# 未加密:可用任意方式直接读取
|
||||
with dlp_io.open(r"D:\Protected\input.pptx", "rb") as stream:
|
||||
data = stream.read()
|
||||
```
|
||||
|
||||
判断原理:DLP 透明加密在磁盘上存密文,白名单进程读到明文、非白名单工具(certutil)读到原始盘内字节;加密文件与未加密文件的 attrib 属性、ADS、大小完全一致,只有内容可区分。`is_encrypted()` 先比较 certutil 原始哈希与当前进程视图哈希:不一致则文件已加密且当前进程是白名单;一致时存在歧义(文件未加密,或文件已加密但当前进程是非白名单 EXE),再比较 helper 视图与当前进程视图的前 64 KiB 定案。两种运行环境(Python/pyd 与打包 EXE)结果都正确。
|
||||
|
||||
代价:未加密文件需要一次完整 certutil 哈希、一次本地完整读取和一次 helper 前 64 KiB 读取;大文件请缓存判断结果,不要每次读取前重复调用。helper 未启动时会复用懒加载的默认 session,结束后照常 `dlp_io.shutdown()`。非 Windows 平台直接返回 `False`。
|
||||
|
||||
## 未加密写入
|
||||
|
||||
写入目标始终是「磁盘上保存未加密文件」:
|
||||
|
||||
- 打包为 EXE(非白名单进程):原生直写天然落盘明文,选中直写通道。
|
||||
- Python 调试 / pyd(白名单进程):部分 DLP 策略会加密白名单进程的写入。首次写某个后缀时库会用临时探针文件实测直写是否落盘明文(用 certutil 原始哈希校验);若直写会被加密,自动改走 PowerShell 中转通道——字节经 stdin 管道传给非白名单的 powershell.exe 子进程写盘,不经过任何磁盘临时文件。通道按文件后缀缓存;两个通道都不可用时抛出 `DlpWriteError`,绝不静默写出密文。
|
||||
|
||||
可用环境变量跳过探测、强制指定通道(值为 `direct` 或 `powershell`):
|
||||
|
||||
```powershell
|
||||
$env:DLP_IO_WRITE_CHANNEL = "powershell"
|
||||
```
|
||||
|
||||
探测按后缀缓存,注意 DLP 策略若按目录区分,探针结果可能与目标目录不同;此时建议用环境变量显式指定通道。
|
||||
|
||||
## 配置和生命周期
|
||||
|
||||
默认 session 在第一次读取时懒启动,并被后续读取复用:
|
||||
@@ -154,6 +190,7 @@ finally:
|
||||
- `DlpProtocolError`:协议版本、控制消息或响应结构无效。
|
||||
- `DlpTransportError`:helper 在显式 EOF 前断开,或文件传输被截断。
|
||||
- `DlpSessionBusyError`:同一个 session 已有活动 stream。
|
||||
- `DlpWriteError`:没有任何写入通道能落盘未加密文件,或 PowerShell 中转写入失败。
|
||||
|
||||
helper 启动或读取失败时,库会显式报错并且不回退到当前 EXE 直接读取。DLP 直读可能返回合法长度的密文;静默回退会把数据损坏伪装成成功。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user