Files
dlp-io/docs/DLP_IO_LIBRARY.md
T
2026-07-31 16:42:59 +08:00

6.6 KiB
Raw Blame History

dlp-io

dlp-io 为 Windows DLP 透明加密环境提供接近 io.open 的 Python 文件 API。非白名单进程负责业务逻辑和写入;文件读取由已获 DLP 白名单授权的 Python helper 完成,再通过经过认证的 Windows Named Pipe 返回明文字节。

当前版本为 dlp-io==0.1.0distribution 名是 dlp-ioimport 名是 dlp_io

安装

发布物托管在 Gitea Release 页面,由 .gitea/workflows/publish-dlp-io.yaml 从 immutable tag dlp-io-vX.Y.Z 自动构建并上传,全部产物在 CI runner 上编译,不依赖本地环境。

Release 页面:https://gitea.docker.antior.cn/antior/dlp-io/releases

每个版本包含以下文件:

  • dlp_io-X.Y.Z-py3-none-any.whl:纯 Python wheel,适用于任何 CPython >= 3.10 环境。
  • dlp_io-X.Y.Z-cp310-cp310-win_amd64.whlcp314pyd wheelWindows 专用,按解释器版本区分;整个库由 Cython 编译为单个二进制 .pyd,功能与纯 Python 版完全一致,可按对源码保护的要求选用。
  • dlp_io-X.Y.Z.tar.gzsdist 源码包。
  • dlp_io.pydlp_io.cp310-win_amd64.pydcp314:免安装单文件,与 wheel 内容一致;直接放进项目目录(或加入 PYTHONPATH)即可 import dlp_io,适合不便使用 pip 的环境。

按解释器版本选择对应资产,可直接用 pip 安装 URL。Windows PowerShell

# 纯 Python 版(任意平台)
py -m pip install https://gitea.docker.antior.cn/antior/dlp-io/releases/download/dlp-io-v0.1.0/dlp_io-0.1.0-py3-none-any.whl

# pyd 版(示例为 CPython 3.13,其它版本替换文件名中的 cp313)
py -3.13 -m pip install https://gitea.docker.antior.cn/antior/dlp-io/releases/download/dlp-io-v0.1.0/dlp_io-0.1.0-cp313-cp313-win_amd64.whl

也可以先从 Release 页面下载 wheel,再 py -m pip install <文件路径>。下载 Release 资产不需要 token;发布只能在 CI 中通过注入的 GITHUB_TOKEN 完成,发布凭据不得写入命令行、URL 或 tracked 文件。

调用方需要安装 dlp-io。白名单 Python 无需安装该包:helper 源码由调用方以 UTF-8 通过 stdin 注入,且只依赖 Python 标准库,不会在磁盘创建临时 .py 文件。

运行环境必须是 Windows,并且机器上已有一个真正具备 DLP 明文读取权限的 Python。解释器查找顺序为:

  1. DLP_IO_PYTHON
  2. DATAPACKER_DLP_PYTHON(兼容 DataPacker
  3. python
  4. py -3

生产环境优先把 DLP_IO_PYTHON 设置为审批过的 Python 绝对路径。

io 风格用法

把原来的 io.open 或内置 open 改成 dlp_io.open 即可。纯读取走 helper;写入、追加和独占创建仍使用调用进程的原生文件 API。

from pathlib import Path

import dlp_io


source = Path(r"D:\Protected\input.txt")
output = Path(r"D:\Output\result.txt")

with dlp_io.open(source, "r", encoding="utf-8", newline="") as reader:
    text = reader.read()

with dlp_io.open(output, "w", encoding="utf-8", newline="\n") as writer:
    writer.write(text.upper())

dlp_io.shutdown()

dlp_io.open() 保留 io.open() 的参数名和位置习惯,包括 bufferingencodingerrorsnewlineclosefdopener

模式路由规则:

  • 路径型 rrtrb:通过 helper 读取。
  • 路径型 wax:使用原生 open 写入。
  • 整数文件描述符或自定义 opener:使用原生 open
  • 路径型 + 更新模式:显式抛出 io.UnsupportedOperation
  • 路径读取配合 closefd=False:与标准 API 一样抛出 ValueError
  • rb 配合 buffering=0:返回 raw stream;默认返回 buffered reader。
  • 文本模式的默认 encoding 与当前 Python io.open 一致;跨机器文件请显式传 encoding="utf-8"

配置和生命周期

默认 session 在第一次读取时懒启动,并被后续读取复用:

import dlp_io

dlp_io.configure(
    python_executable=r"C:\ApprovedPython\python.exe",
    startup_timeout=30,
)

try:
    with dlp_io.open(r"D:\Protected\payload.bin", "rb") as stream:
        header = stream.read(64)
finally:
    dlp_io.shutdown()

必须在默认 session 启动前调用 configure()。需要更换解释器时,先 shutdown(),再重新配置。shutdown() 和 session 的 close() 都是幂等操作。

显式 session

库或服务代码可以显式持有 session,避免全局状态:

import dlp_io

with dlp_io.DlpSession.start(
    python_cmd=[r"C:\ApprovedPython\python.exe"],
    timeout=30,
) as session:
    with session.open(r"D:\Protected\archive.dat", "rb") as stream:
        stream.seek(-32, 2)
        trailer = stream.read()

一个 session 同时只允许一个活动读取 stream。请关闭当前 stream 后再打开下一个;并行读取应由调用方创建彼此独立的 session。

兼容既有代码的全局 patch

只有当第三方代码无法逐个改为 dlp_io.open() 时,才临时 patch builtins.openio.open

import dlp_io

dlp_io.configure(python_executable=r"C:\ApprovedPython\python.exe")
dlp_io.install_open_patch()
try:
    run_legacy_application()
finally:
    dlp_io.uninstall_open_patch()
    dlp_io.shutdown()

在打包入口中,应先 import 完业务模块和本地资源,再安装 patch。patch 只路由路径型纯读模式,重复安装和卸载是幂等的。它不会拦截 os.open,也无法拦截 C 扩展内部绕过 Python open 的读取。

如果应用自己管理 session,可以把 session.open_raw 传给 install_reader_patch()

错误和安全边界

主要异常均继承 DlpIoError

  • DlpConfigurationError:平台、配置或参数不成立。
  • DlpHelperStartError:白名单 Python 启动、源码注入或握手失败。
  • DlpProtocolError:协议版本、控制消息或响应结构无效。
  • DlpTransportErrorhelper 在显式 EOF 前断开,或文件传输被截断。
  • DlpSessionBusyError:同一个 session 已有活动 stream。

helper 启动或读取失败时,库会显式报错并且不回退到当前 EXE 直接读取。DLP 直读可能返回合法长度的密文;静默回退会把数据损坏伪装成成功。

版本 1 会在 EOF 和 seek 重连时检测文件 size 的截断或增长,但不提供文件快照,也不能识别读取期间发生的同尺寸内容替换;调用方应避免并发修改输入文件。

每次 session 使用随机 32-byte authkeyAF_PIPE 连接执行 challenge-response 认证;协议控制消息和数据帧都有明确大小边界,零长度数据帧是唯一 EOF。

卸载

py -m pip uninstall dlp-io