后端Web框架【免费下载链接】playframeworkThe Community Maintained High Velocity Web Framework For Java and Scala.项目地址https://gitcode.com/gh_mirrors/pl/playframework点击查看免费下载本文是 Play Framework 2.5 系列迁移文档的核心章节系统讲解旧版Crypto工具对象被废弃的原因、其背后消息认证MAC与对称加密AES设计上的安全隐患以及迁移到 Kalium、Tink 或纯 JCA 的三条推荐路径。读完本文你将理解 Play 为何将密码学能力拆分为CookieSigner、CSRFTokenSigner等专用 trait并能为自己的应用选择安全、合适的替代实现。背景从Crypto单例到专用 Signer Trait从 Play 1.x 起Play 框架就内置了一个名为Crypto的对象提供若干密码学操作并被 Play 内部使用。虽然该对象从未在官方文档中被正式介绍但它的 scaladoc 中将其描述为密码学工具cryptographic utilities并附带了一段重要警告这些工具旨在提供便利但使用该类之前务必阅读每个方法的文档并理解加密背后的概念。安全加密是困难的任何东西都无法替代对密码学的充分理解。这些方法并不适合所有加密需求。然而经过实践检验以便利工具的形式提供密码学能力这一思路被证明并不可行。因此从2.5.x开始Play 将原本属于Crypto的框架专用功能拆分成了三个独立的 trait并正式将Crypto单例对象标记为deprecated废弃新组件职责CookieSigner为 Cookie尤其是 Session Cookie提供消息认证码MAC签名CSRFTokenSigner生成与校验 CSRF 令牌防止 BREACH 攻击AESSigner对称加密相关的签名辅助AES 相关能力从当前仓库源码可以验证这一拆分结果CookieSigner与CSRFTokenSigner分别定义在 core/play/src/main/scala/play/api/libs/crypto/CookieSigner.scala 与 core/play/src/main/scala/play/api/libs/crypto/CSRFTokenSigner.scala并提供对应的 Java 接口版本 core/play/src/main/java/play/libs/crypto/CookieSigner.java。依赖注入时可通过 CryptoComponents 获取cookieSigner()与csrfTokenSigner()两个组件。关联阅读Play 2.5 总迁移指南 Migration25.md 中 Crypto Deprecated一节也明确指出加密迁移方案取决于你的使用场景尤其是是否涉及不安全的密码学原语构造推荐顺序是能上 Kalium 就上 Kalium否则用 Tink 或直接用 JCA。消息认证Message Authentication为什么不应滥用Crypto.signPlay 使用Crypto.sign方法为 Session Cookie 提供消息认证。该方法在内部用于对 Session Cookie 进行签名但官方明确建议不应在签名 Cookie 之外的场景使用Crypto.sign理由有以下三点。MAC 算法独立性Play 需要保留升级 HMAC 的空间Play 当前使用HMAC-SHA1对 Session Cookie 进行签名与校验。HMAC基于哈希的消息认证码是一种利用密钥即play.crypto.secret配置的应用密钥配合消息摘要函数认证数据未被篡改的密码学函数此处采用的摘要函数是 SHA-1。虽然 SHA-1 近年遭受了若干攻击但当它与 HMAC 配合用于消息真实性验证时仍然是安全的。关键在于Play 需要保留按需切换到其他 HMAC 函数的灵活性因此 HMAC 的具体选择不应成为公共 API 的一部分。如果Crypto.sign被大量外部代码直接依赖Play 内部升级 HMAC 算法的自由度就会受限这正是它不应作为公共 API 的理由之一。从仓库源码看当前DefaultCookieSigner的默认实现确实仍固定使用HmacSHA1算法见 CookieSigner.scala并通过Mac.getInstance(HmacSHA1)获取 JCE 提供的 MAC 实例最后用Codecs.toHexString输出十六进制签名字符串def sign(message: String): String { sign(message, secretConfiguration.secret.getBytes(StandardCharsets.UTF_8)) }其 Scala 与 Java 接口均提供了两个重载一个使用应用密钥签名一个显式传入自定义key字节数组签名。单元测试 CookieSignerSpec.scala 验证了这两种签名路径——例如使用密钥0123456789abcdef对文本Play Framework 2.0签名得到的 HMAC-SHA1 十六进制摘要为94f63b1470ee74e15dc15fd704e26b0df36ef848。潜在的新功能需求Session 缺少过期时间Play 目前只对 Session Cookie 进行签名但没有为其附加任何会话超时或过期时间。这意味着只要攻击者能接触到请求active attacker就可以把一个 Session Cookie 替换成另一个 Session Cookiecookie swapping。要解决这类问题Play 可能需要给 Session 引入时间戳等额外机制——而这类演进同样要求签名逻辑不能过早固化到公共 API 中。误用为密码哈希MAC 不是密码存储方案请勿将Crypto.sign或任何形式的 HMAC 用于密码哈希这是文档中特别强调的告诫。原因是两者的设计目标截然相反MAC 追求快与廉价签名/验签需要高频执行设计上要求计算开销小密码哈希追求慢与昂贵为了抵抗暴力破解与 GPU 加速攻击密码哈希需要刻意引入计算成本。因此正确的密码存储应使用scrypt、bcrypt 或 PBKDF2等专用算法。在 Java 生态中jBCrypt是最广为人知的 bcrypt 实现之一。对称加密Symmetric EncryptionCrypto.encryptAES的安全隐患Crypto还包含两个对称加密方法Crypto.encryptAES与Crypto.decryptAES。这两个方法从未被 Play 内部使用但社区投入了大量精力对其安全性进行审查。这两个方法同样将被废弃并可能在未来的版本中移除。与前面的警告一致这两个方法并非普遍安全——存在若干常见的工作模式mode of operation在使用它们时是不安全的。下面逐一分析Crypto.encryptAES存在的密码学问题。再次强调Crypto.encryptAES从未在 Play 内部被直接使用因此这不是Play 自身的安全漏洞。无认证的流密码AES-CTR 的可塑性MalleabilityCrypto.encryptAES默认使用AES-CTR模式。CTR 模式属于流密码类工作模式它只提供加密confidentiality不提供认证authentication——也就是说活跃攻击者可以把密文内容替换成其他内容而不被发现。这种密文可被篡改的性质被称为可塑性malleability在特定条件下甚至可能让攻击者恢复出明文或任意改写消息内容。业界有两种缓解该问题的标准构造Encrypt Then MAC先加密后签名对密文再施加一个 MAC认证加密Authenticated Encryption直接使用同时提供认证与加密的算法例如AES-GCM。Play 内部用Crypto.encryptAES加密 Session Cookie 的内容该内容本身已附加了 MAC。由于 Play 采用的是Encrypt Then MAC构造因此它并不易受此类攻击——但那些在没有 MAC 保护的情况下使用对称加密的用户则存在潜在风险。文档同时建议不要自行实现 Encrypt-Then-MAC 构造正确做法是直接使用认证加密让认证与加密在同一算法中完成详见下文迁移章节。违反密钥分离原则Key Separation Principle虽然AES HMAC被认为是安全构造但 Play 使用密钥的方式存在一个设计问题密钥分离原则要求一把密钥只服务于一个目的。而在Crypto时代play.crypto.secret不仅用于签名还被Crypto.encryptAES用于加密——同一把密钥被复用于两个不同用途。文档引用密码学社区的分析指出对于HMAC vs AES这一组合目前没有已知的密钥混用干扰密码学家的普遍共识是 AES 与 SHA-1/SHA-256 足够不同同一密钥同时用于 AES 与 HMAC 不应产生实际问题。因此对于正在使用Crypto.encryptAES的用户密钥混用并不会立刻带来安全漏洞。但随着应用规模增大密钥分离原则可能在另一个维度被违反如果Crypto.encryptAES被用于多种不同用途同样建议为不同用途分配独立密钥。工作模式的全局配置问题如前所述AES 支持多种工作模式而不同模式可能需要不同的附加安全措施。Play 却通过play.crypto.aes.transformation这一配置项提供全局的工作模式配置——该配置会影响整个应用包括所有使用Crypto.encryptAES的第三方库。这样一来改动这一配置项对整个应用的实际影响范围很难预估这也成为其被废弃的另一个理由。迁移路径Migration从Crypto平滑过渡从Crypto功能迁移有以下几条路径按推荐优先级排序Kalium、Tink、纯 JCA。Kalium首选基于 libsodium 的高级密码学库如果你的生产环境可以控制二进制依赖且没有必须使用 NIST 批准算法的外部要求推荐使用Kalium——它是 libsodium 库的封装。需要Crypto.sign的 MAC 替代品使用org.abstractj.kalium.keys.AuthenticationKey它实现了HMAC-SHA512/256需要Crypto.encryptAES的对称加密替代品使用org.abstractj.kalium.crypto.SecretBox它实现了secret-key authenticated encryption密钥认证加密天然同时提供加密与认证。注意Kalium 要求环境中安装 libsodium 二进制库官方建议安装经你亲自验证过的源码构建版本。Tink纯 Java 且支持 NIST 批准算法的选择如果你需要纯 Java 方案或必须依赖 NIST 批准的算法可以使用Tink——一个构建在 JCA 之上的高层密码学库。文档特别说明Tink 的成熟度与支持力度不如 libsodium / Kalium因此Kalium 仍然优先。需要Crypto.sign的 MAC 替代品使用com.google.crypto.tink.mac.MacKeyTemplates需要Crypto.encryptAES的对称加密替代品使用com.google.crypto.tink.aead.AeadKeyTemplates。JCA保持原算法不变的最低改动方案Kalium 与 Tink 使用的密码学原语都与Crypto不同。如果希望在不改变底层算法如继续使用 AES 与 HMAC的前提下完成迁移最合适的做法是把 Crypto 库中的相关代码抽取到用户自己的类中由应用层自行维护再按安全最佳实践如使用认证加密、隔离密钥用途加以改造。迁移决策速查你的需求推荐方案替代Crypto.signMAC且环境可控KaliumAuthenticationKeyHMAC-SHA512/256替代Crypto.signMAC且需纯 Java/NISTTinkMacKeyTemplates替代Crypto.encryptAES认证加密且环境可控KaliumSecretBox替代Crypto.encryptAES认证加密且需纯 Java/NISTTinkAeadKeyTemplates必须保持 AES/HMAC 原算法不变抽取 Crypto 源码为用户级类自行加固当前仓库中的替代实现Signer 是如何工作的迁移到 2.5 之后Play 自身的 Session Cookie 签名链路已经完整建立在CookieSigner之上可以在仓库源码中直接印证Session.scala 中DefaultSessionCookieBaker与LegacySessionCookieBaker均通过构造器注入CookieSigner其中LegacySessionCookieBaker的注释明确写着以 Play 2.5.x 风格签名 Session CookiecookieSigner参数标注为通常是 HMAC-SHA1CookieSignerProvider见 CookieSigner.scala从SecretConfiguration构建DefaultCookieSigner而SecretConfiguration定义在 HttpConfiguration.scala其默认密钥为changeme并支持通过配置指定 JCE Provider密钥与 Provider 的配置项为play.http.secret.provider旧配置名play.crypto.provider仍可通过 deprecated 机制读取见 HttpConfiguration.scalaDefaultCookieSigner在实例化 MAC 时若指定了 Provider 则优先使用Mac.getInstance(HmacSHA1, p)否则使用平台默认 JCE Provider。CSRFTokenSigner 的防 BREACH 设计CSRFTokenSigner的默认实现CSRFTokenSigner.scala值得专门一提它展示了 Play 在签名场景下的实战密码学设计signToken会将当前时间戳作为 nonce 与原始 token 拼接后签名输出格式为签名-时间戳-原始token。其核心目的正如源码注释所述主要为了抵御BREACH 漏洞——在不改变 token 实际值的前提下让 token 每次请求看起来都是随机的extractSignedToken按-分割并校验签名校验时使用MessageDigest.isEqual进行常数时间比较避免时序侧信道攻击generateToken使用SecureRandom生成 12 字节随机数并转为十六进制默认实现还会在初始化时调用random.nextBytes(new ArrayByte)进行 440 位的自播种对应 NIST SP800-90A 建议以兼容旧版 Windows 上 SHA1PRNG 的弱自播种问题。这些实现细节表明即使是为 Cookie 签名这一看似简单的需求Play 也内建了对抗活跃攻击者nonce 化、常数时间比较与熵不足SecureRandom 自播种的多重防护——这正是密码学 API 应由框架谨慎设计、而非暴露给用户随意拼装这一迁移主旨的最佳注解。进一步阅读密码学 API 的设计远比表面看起来复杂。文档推荐了以下关于密码学设计与 API 复杂性的公开资料供深入研究The Long Journey from Papers to Software: Crypto APIsWhats Wrong with Crypto API DesignReal World Crypto 2015: Error-prone cryptographic designs (djb)及其配套幻灯片此外OWASP 的Cryptographic Storage Cheatsheet是学习安全加密存储实践的重要参考资料。理解这些资料有助于在迁移到 Kalium / Tink / JCA 时做出正确的算法选择与构造决策。赞分享后端Web框架【免费下载链接】playframeworkThe Community Maintained High Velocity Web Framework For Java and Scala.项目地址https://gitcode.com/gh_mirrors/pl/playframework点击查看免费下载相关推荐Youku-mPLUG中文数据集首个大规模中文视频文本对在生成任务中的应用Youku mPLUG中文数据集首个大规模中文视频文本对在生成任务中的应用 随着AIGC技术的飞速发展视频生成领域对高质量中文数据的需求日益迫切。然而长期以密码学后端如何在 ESP-IDF 中快速获取 WiFi TSF 时间戳一份完整指南如何在 ESP IDF 中快速获取 WiFi TSF 时间戳一份完整指南 想在 ESP IDF 项目里拿到微秒级精度的 WiFi 时间参考本文带你用 esp物联网嵌入式商品图加一条差评分类模型会更聪明吗PyTorch 多模态学习快速上手指南商品图加一条差评分类模型会更聪明吗PyTorch 多模态学习快速上手指南 pytorch deep learning 是一套从零到一讲透 PyTorch 的示例工程教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考