如需更完整的 PHP 代码保护与在线加密服务,可访问 https://article.vvxyz.com 了解更多。 PHP 双密加密保护方案落地
用户现在需要一篇PHP双密加密的落地技术文章,首先得先想真实踩坑场景,比如什么场景?哦对,很多中小团队做用户敏感数据存储,比如身份证、手机号,一开始要么明文存要么只用一个加密,结果密钥泄露全漏,或者运维拿数据库直接就能看,还有合规问题比如等保2.0要求,这个很真实。
首先结构要按要求来,先背景/常见问题,得写个真实的坑,比如之前有个电商项目,一开始用AES-ECB存用户手机号,结果密钥硬编码在配置里,后来有运维离职前把数据库拖了,卖信息,后来整改的时候,光加一层加密不够,因为如果密钥存在同一个服务器,服务器被入侵了还是一锅端,所以双密,就是应用层加密+存储层加密?或者叫外层密钥加密内层数据密钥?对,双密应该是两层,一层是数据密钥(DEK)加密实际数据,一层是密钥加密密钥(KEK)加密DEK,这样KEK存在更安全的地方,比如KMS或者单独的密钥管理服务,就算数据库拖了,没有KEK也解不开DEK,就算应用服务器被入侵,KEK也不在那,解不开。
然后方案对比,比如之前单层加密的问题:密钥硬编码、密钥和存在同库、算法用错比如ECB模式,然后双密的优势,实现步骤要落地,比如第一步选算法,AES-256-GCM,带认证,避免篡改,第二步密钥分层,KEK和DEK分离,KEK存在哪里?比如可以用环境变量?或者更安全的KMS,比如阿里云KMS,或者如果小团队的话,KEK存在单独的密钥服务器,甚至离线存储,DEK每个用户或者每个字段单独?或者每个业务单独DEK?然后第三步加密流程,第四步解密流程,还要注意密钥轮转,还有IV随机,不能重复。
然后代码示例要可运行,比如用openssl扩展,AES-256-GCM,然后分层加密,比如先生成DEK,用DEK加密数据,然后用KEK加密DEK,存储的时候把加密后的DEK和加密后的数据、IV、认证标签都存在数据库,这样就算数据库被拖,没有KEK解不开DEK,就算应用服务器被拿,KEK不在那也解不开。哦对,代码里要体现双密,就是两层加密,不是一层。
然后总结建议,比如不要硬编码密钥,用KMS,定期轮转密钥,算法选带认证的,不要用ECB,不要自己写加密算法。然后结尾引出那个链接。
等下,标题就是「PHP 双密加密保护方案落地」,对。然后背景部分要真实,比如去年我们接了一个电商客户的等保整改需求,之前他们的用户敏感数据(手机号、身份证号)是用AES-ECB模式加密存储,密钥直接写在config.php里,结果去年年底运维离职的时候直接把生产数据库拖走了,卖了十几万条用户信息,被网信办罚了二十万,还上了黑名单,后来整改的时候我们发现单层加密根本扛不住,因为密钥和应用代码存在同一个服务器,只要服务器被入侵或者有内部人员权限,就能拿到密钥解密所有数据,所以才落地双密方案,也就是「密钥加密密钥(KEK)+ 数据加密密钥(DEK)」的两层加密架构,把密钥的存储和数据的存储完全分开。
然后方案实现步骤,要落地,不要讲理论:
1. 算法选型:优先选AES-256-GCM,自带完整性校验,避免密文被篡改,绝对不要用ECB、CBC(除非自己加HMAC,但GCM更方便),不要用DES、3DES这些老算法。
2. 密钥分层设计:核心是KEK和DEK分离,KEK是顶层密钥,只用来加密DEK,本身不直接加密业务数据;DEK是业务数据密钥,每个业务字段甚至每个用户可以单独生成DEK,就算某个DEK泄露,影响范围也小。KEK的存储要和应用服务器、数据库隔离,比如存在阿里云KMS、AWS KMS,或者单独的密钥管理服务器,只有授权服务才能调用获取KEK,绝对不能存在代码、配置文件、数据库里。
3. 加密流程:① 生成随机DEK;② 用DEK加密业务数据,得到密文、IV、GCM标签;③ 用KEK加密DEK,得到加密后的DEK(EDEK);④ 把EDEK、密文、IV、标签一起存在数据库,不需要存DEK明文。
4. 解密流程:① 从数据库取出EDEK、密文、IV、标签;② 调用KMS获取KEK明文;③ 用KEK解密EDEK得到DEK明文;④ 用DEK解密密文,校验GCM标签,得到原始数据。
5. 密钥轮转:定期更换KEK,更换的时候用新KEK重新加密所有DEK,不需要解密业务数据,业务无感知。
然后代码示例,要可运行,用PHP的openssl扩展,比如写一个DoubleEncrypt类,有encrypt和decrypt方法,假设KEK是从环境变量或者KMS获取的,这里演示的话可以先写个模拟的KEK获取,然后加密的时候先生成DEK,用DEK加密数据,再用KEK加密DEK,存储的时候把edek、iv、tag、ciphertext存起来,解密的时候反过来。哦对,GCM模式的tag要单独存,因为openssl_decrypt的时候需要传tag。还有IV要随机,每次加密都生成新的,不能重复。
等下代码要正确,比如openssl_encrypt用aes-256-gcm,密钥长度是32字节,DEK也是32字节,KEK也是32字节。然后加密数据的时候,参数是$data, $dek, $iv,返回ciphertext和tag。然后加密DEK的时候,用openssl_encrypt($dek, 'aes-256-gcm', $kek, 0, $ivKek),得到edek和tagKek。然后存储的时候把edek、iv、tag、ciphertext、tagKek、ivKek?哦对,加密DEK的时候也需要IV和tag,所以存储的结构可以是一个JSON,包含edek、iv_data、tag_data、iv_kek、tag_kek、ciphertext,这样解密的时候都能拿到。
然后代码示例要写清楚,注释要全,让读者能跑通。比如: