ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python 密码学最佳实践:语言边界、RSA 陷阱与 FFI 突围路径

Python 密码学最佳实践:语言边界、RSA 陷阱与 FFI 突围路径 【免费下载链接】publicationsPublications from Trail of Bits项目地址https://gitcode.com/GitHub_Trending/pu/publications点击查看免费下载本文基于 Trail of Bits 首席安全工程师 Paul Kehrer 在 PyCon AU 2019 的演讲《Best Practices for Cryptography in Python》整理成文。文章以演讲的完整脉络为骨架——从密码学到底是什么的问题定义到 Python 实现加密算法的语言级限制再到 RSA 反例、威胁模型与 FFI 突围方案——并结合本仓库 publications 中同主题的系列演讲与源码级资源进行补充帮助读者建立一套什么时候 Python 适合做密码学、什么时候不适合、不适合时如何补救的完整决策框架。演讲背景谁在什么场合讲了什么本演讲出自 2019 年 8 月 2 日的 PyCon AU 大会演讲者是 Paul Kehrer时任 Trail of Bits 首席安全工程师同时是 Python Cryptographic AuthorityPyCAPython 加密权威组织的核心开发者长期维护cryptography、PyNaCl、bcrypt、pyOpenSSL等 Python 生态最主流的加密库。完整的演讲元数据与幻灯片分别见 README.md 和 presentation.pdf。演讲的第一张技术内容页给出了全篇的核心结论只有一句话且自带限定条件Secure cryptography is possible in Pythonrestrictions apply—— 在 Python 中做出安全的密码学是可能的但有限制。这句先给结论、再讲限制的开场奠定了整场演讲的基调不神化 Python也不一棍子打死而是精确地划出 Python 的适用边界并为边界之外的场景给出工程化出路。密码学到底是什么先定义问题再讨论语言在讨论Python 能不能做密码学之前演讲先回到了第一性原理——密码学要解决的问题是什么在存在对手的前提下安全地通信与传递信息对手可能是被动的只能窃听无法篡改或主动的可以注入、重放、篡改消息通信可能是同步的双方同时在线的握手式通信或异步的如签名、证书这类离线验证场景需要保护的信息不一定是文件也可以是密钥、口令、协议消息等任意数据形态。演讲随后点出了密码学软件工程中一个常被低估的事实要写出安全的密码软件算法本身和具体实现必须同时正确。算法层面的安全如 RSA 的数学性质与实现层面的安全如常数时间、内存清零是两条独立的失败路径任意一条被攻破整个系统就不可信了。本次演讲的范围聚焦实现层面的语言限制演讲明确界定了自己的讨论范围Implementation-based issues caused by language-level restrictions——即由语言层面的限制所引发的实现问题。这一定位很重要它把讨论从协议设计是否合理密钥管理是否妥当等更宏大的话题中剥离出来聚焦到一个具体、可回答的问题当你想用 Python 这一门语言把某个加密算法写出来并跑在生产环境时Python 的语言特性会在哪些环节、以何种方式损害安全性实现加密算法需要什么四项硬性条件演讲用一页幻灯片列出了实现加密算法这个任务的真实需求清单每一项都是硬约束低层流程控制防止数据相关的分支加密代码中不能出现依赖秘密数据的条件跳转否则攻击者可通过计时观测恢复密钥——这就是时序侧信道timing side channel的根源对缓存、SIMD 指令等的精细控制现代 CPU 的缓存行为、向量指令的选择都会在物理层泄漏信息算法实现者需要有能力控制到这一层精确的内存分配与擦除密钥等敏感数据需要可预测的分配时机且用完后必须可靠地清零而不是交给 GC 或引用计数在不可控时刻回收尽可能高的执行速度大数模幂、椭圆曲线点乘等运算是计算密集型的性能本身就是安全性的组成部分慢到不可用的加密实现会迫使开发者绕开它、走向不安全的自定义捷径。演讲用一个略带自嘲的句子总结了这份需求清单的推论Unfortunately this means it is mostly written in C——遗憾的是这意味着密码学实现大多是 C 语言写的。原因被归纳为三点Ubiquity普遍性、Speed速度以及一条黑色幽默式的第三条The memory unsafety industrial complex needs CVEs——内存不安全的工业综合体需要源源不断的CVE。这句玩笑的背后是一个严肃事实加密库长期以 C 等不安全的系统语言实现一方面是因为没有更好的选择另一方面也为攻击面埋下了大量内存安全漏洞。用 Python 实现加密算法的警示案例RSA 与 pow()为了具体展示Python 实现加密算法到底难在哪里演讲选择了 RSA 作为例子——并且每翻一页幻灯片上劝阻语气都更重一分从 do not use RSA 到 I beg of you, do not use RSA再到 No! Stop! 与 please do not use RSA, it is so bad。RSA 的数学核心只有两对公式签名/验签S M^d (mod N)M S^e (mod N)加密/解密C M^e (mod N)M C^d (mod N)看起来极其简洁而 Python 恰好提供了一个一步到位的内建函数pow(base, exp, mod)于是签名可以写成sig pow(msg, d, n) # 签名 msg pow(sig, e, n) # 验签演讲反复强调do not use RSA and also do not do this——既不要用 RSA也不要用这种方式实现它。原因在于RSA 的安全性从来不在这一行数学表达式里而在于大量教科书不会写的工程细节大数运算必须常数时间执行模幂的迭代次数、每轮是否执行乘法的分支都不能泄漏指数d的比特位需要精确的内存管理中间值尤其是私钥指数d用后必须清零需要标准的填充方案如 PSS/OAEP而填充校验的失败路径必须统一否则就会引入 padding oracle 攻击。而 Python 的pow(msg, d, n)在 CPython 解释器层面走的是通用大整数实现其分支与运算时长对数据敏感既无法满足常数时间要求也无法对中间状态做可控擦除。演讲专门展示了一个真实的 2048 位模数N长什么样约 617 位十进制数字直观说明当你把这些位数的模幂运算是交给一个逐比特分支解释执行的运行时时侧信道攻击面是灾难性的。需要强调的是不要用 RSA并非 Python 特有的话题而是整个行业在 20 多年攻击史中形成的共识。本仓库中同属 Cryptography 分类的另一场演讲 Seriously, stop using RSA 对此有完整的论证RSA 是内在脆弱的密码系统弱参数难以检查、性能压力迫使开发者走捷径、padding oracle 攻击在其被发现二十年后依然肆虐——理论上可以实现正确的 RSA但实践已经证明这几乎不可达成。确立什么才是重要的威胁模型驱动一切在展示了 RSA 这一令人沮丧的反例之后演讲紧接着给出了最重要的方法论转折——Establish what matters确立什么才是重要的具体包含三层意思明确定义你考虑防护的威胁集合威胁模型threat model必须先行而不是默认所有攻击都必须防住很多语言层面的限制在你的具体场景中可能根本无关紧要例如一个只在本机、单进程、非交互式环境中处理密钥的脚本与一个面对网络级主动攻击者的 TLS 终端面临的风险完全不同存在强大的变通方案workarounds可用语言短板不是死局下一节要讲的 FFI 就是最核心的变通手段。这层威胁模型优先的思想正是演讲标题中Best Practices的精髓先问自己保护什么、防谁再决定用什么工具、在哪里实现。这也是安全工程区别于套模板的关键——离开威胁模型的最佳实践往往是伪实践。FFIPython 的加密超能力演讲用整整一节来介绍 Python 在密码学领域真正的优势所在FFIForeign Function Interface外部函数接口。Python 对讲 C ABI 的语言拥有丰富的 FFI 能力通过cffi与ctypesPython 代码可以直接调用原生native代码。这条桥的价值体现在两个方向获取安全加密所需的一切特性把真正敏感的运算下沉到经过审计的、常数时间的、能精确控制内存的原生加密库中执行Python 侧只负责传递数据、编排流程在难用的加密库之上构建 Pythonic API原生加密库如 OpenSSL、libsodium的 C API 往往原始且反直觉FFI 层可以封装出一套符合 Python 习惯的、类型安全的高层接口让普通开发者无需直接面对 C API 的复杂度。这恰恰是演讲者本人长期维护的 PyCA 生态的实践路径。以演讲中提到的 PyNaCl演讲者维护的项目之一为例其典型用法是绑定到 libsodium 这类经受考验的原生实现上为开发者提供高层的、难以误用的 API。同样的思路也延续到了本仓库中收录的后继演讲在 Building a Rusty path validation library for PyCA Cryptography 与 Implementing X.509 path validation for Python 中PyCA 将 X.509 路径验证这样高风险、高复杂度的逻辑从零用内存安全语言 Rust重新实现并集成进cryptography库——这正是把敏感实现移出 Python、用 FFI 桥接原生代码这一策略在 2019 年之后的新发展被调用的原生代码本身也应当走向内存安全。用演讲的原话概括 FFI 的地位FFI, Pythons cryptographic super power——FFI 是 Python 的加密超能力。它不是 Python 的妥协而是 Python 在密码学领域的正确定位当胶水而不是引擎。额外的缓解措施内存层面的精细控制对于无法完全下沉到原生代码、必须留在 Python 侧处理的敏感数据如密钥材料演讲给出了内存层面的补充缓解措施While byte strings are immutable, bytearrays are not. You can also construct buffer protocol objects from native code to gain even more control.bytes 是不可变的一个密钥如果以bytes存储你将无法就地覆写它——它的内存内容只能等垃圾回收/引用计数在不可控的时机释放期间它可能被交换、被复制、被留在堆的多个副本中bytearray 是可变的需要时可以用它承载敏感数据并在用完后手动将内容覆写为随机或零值从而降低密钥残留的风险buffer protocol 对象更进一步可以从原生代码构造实现了 buffer protocol 的对象从而获得更细粒度的内存控制权例如把密钥固定在不被交换出去的页面上、由原生代码负责清零。这一节虽然只有一页幻灯片却点出了一个在 Python 中极易被忽略的事实即便你的加密运算已经交给原生库密钥在进入/离开原生库边界时经过的那段 Python 内存依然是需要管理的攻击面。结论Python 密码学的正确姿势演讲的收尾页回到开头的结论句并给出了完整的展开Python 中做安全密码学是可能的但通常意味着 Python 是调用底层原生代码的那一层而不是加密算法本身的宿主——Secure cryptography is possible in Python 的真实含义是 Python is what you use to call some underlying native code威胁模型是生死攸关的构建安全软件必然伴随取舍tradeoffs你必须清醒地界定防什么与不防什么而不是追求一个不存在的绝对安全限制是诚实的任何Python 密码学最佳实践都应以承认语言边界为前提再给出跨过边界的工程手段。这套方法论可以沉淀为一份可直接落地的检查清单决策环节应遵循的做法选型优先使用cryptography、PyNaCl等基于成熟原生库OpenSSL、libsodium的 PyCA 生态库而不是自行实现算法算法选择默认选择现代算法如 X25519、Ed25519、AES-GCM并明确避开 RSA 这类教科书易写、工程难安全的方案威胁模型先书面界定保护对象、对手能力、通信同步性再决定敏感运算放在哪一层执行敏感数据内存用bytearray而非bytes承载可覆写的密钥材料需要更精细控制时使用原生 buffer protocol 对象侧信道任何依赖秘密数据的运算都应下沉到常数时间实现的原生代码中不要依赖 Python 解释器的行为延伸阅读仓库内的同主题资源本文涉及的演讲属于本仓库 README.md 中 Cryptography 分类下的系列内容以下资源可帮助你进一步深入Seriously, stop using RSA从攻击史出发系统论证 RSA 为何难以安全实现是本文 RSA 反例的完整展开Building a Rusty path validation library for PyCA CryptographyPyCA 用内存安全语言重写 X.509 路径验证的工程实践是原生代码 内存安全路线的最新演进Implementing X.509 path validation for Python同一工作的配套演讲覆盖实现细节与测试策略Constant-Time Coding Support in LLVM从编译器层面保证常数时间实现不被破坏与演讲中数据相关分支威胁直接呼应。这些演讲共同勾勒出一条清晰的演进线索2019 年PyCA 的核心开发者告诉社区别用 Python 实现加密算法用 FFI 调原生库此后数年同一批人又在把被调用的原生库本身改写成内存安全的 Rust——Python 密码学最佳实践的终点是让每一层都不再需要开发者去赌自己的运气。赞分享【免费下载链接】publicationsPublications from Trail of Bits项目地址https://gitcode.com/GitHub_Trending/pu/publications点击查看免费下载相关推荐掌握Carbon语言避开陷阱的终极指南与高级用法技巧掌握Carbon语言避开陷阱的终极指南与高级用法技巧 Carbon语言作为C的实验性继任者旨在解决现代软件开发中的关键挑战。本文将深入探讨Carbon语编程语言编译器标准库彻底解决Xmake中XMAKE_GLOBALDIR路径配置的5大陷阱与最佳实践彻底解决Xmake中XMAKE_GLOBALDIR路径配置的5大陷阱与最佳实践 你是否遇到过这些诡异问题 在使用Xmake一个基于Lua的轻量级跨平台构建工构建工具开发工具包管理器告别多语言陷阱Django-ModelTranslation 全场景避坑指南与最佳实践告别多语言陷阱Django ModelTranslation 全场景避坑指南与最佳实践 引言多语言开发的隐形雷区 你是否曾遭遇过这些令人抓狂的多语言开发场景后端上一篇ts-jest自定义转换器开发从AST操作到缓存策略下一篇css-loaders REST API集成API请求状态的视觉反馈创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表