PHP获取域名后如何加密存储_PHP域名加密保存技巧【技巧】

4次阅读

php域名加密须先标准化再AES-256-GCM加密:统一小写、去端口、可选去www;密钥用random_bytes(32),IV每次重置,密文含IV+tag+密文三部分;解密须校验tag和域名合法性,密钥轮换需兼容新旧密钥并重加密旧数据。

PHP获取域名后如何加密存储_PHP域名加密保存技巧【技巧】

PHP中域名加密前必须先标准化

直接对原始 $_SERVER['HTTP_HOST']$_SERVER['SERVER_NAME'] 加密是危险的——不同访问方式(带www、不带www、含端口https重定向)会导致同一站点产生多个“不同域名”,后续校验无法匹配。必须先做归一化处理:

  • 统一转小写:strtolower($host)
  • 剥离端口(如 :8080)和协议头(https:// 已不在 HTTP_HOST 中,但需注意反向代理场景)
  • 可选:强制去 www(preg_replace('/^www./i', '', $host)),但需确认业务是否允许子域共用密钥
  • 最终建议格式:$canonicalDomain = rtrim($host, '.')(防尾部点号)

openssl_encrypt() 替代 mcrypt 或简单 base64

mcrypt 已被废弃,base64_encode() 不是加密,只是编码,毫无安全性。真实加密必须用现代 AEAD 模式:

  • 推荐算法'aes-256-gcm'(PHP 7.1+),兼顾安全与性能
  • 密钥必须由 random_bytes(32) 生成,**绝不能硬编码字符串或用 md5/SHA 拼接**
  • 每次加密必须用新 IV:$iv = random_bytes(openssl_cipher_iv_length('aes-256-gcm'))
  • 完整密文需保存三部分:密文 + IV + 认证标签($tag),缺一不可,否则解密失败

示例关键片段:

$cipher = 'aes-256-gcm'; $key = hex2bin('your-32-byte-hex-key-from-config'); // 实际应从环境变量或密钥管理服务读取 $iv = random_bytes(openssl_cipher_iv_length($cipher)); $tag = ''; $ciphertext = openssl_encrypt($domain, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag); $stored = base64_encode($iv . $tag . $ciphertext); // 合并后 Base64 存数据库字段

解密时验证完整性比解密本身更关键

攻击者可能篡改存储的密文,若只检查 openssl_decrypt() 返回 false 就报错,会暴露侧信道(如通过响应时间判断密文结构)。正确做法:

立即学习PHP免费学习笔记(深入)”;

  • 先完整解析出 IV、tag、密文三段(长度固定:iv_len=12, tag_len=16 for GCM)
  • 调用 openssl_decrypt() 时传入 $tag,函数内部自动校验;若 tag 错误,返回 false 且**不泄露任何中间状态**
  • 解密成功后,仍需用 hash_equals() 校验解密结果是否为合法域名(防空字节截断或 NULL 字符注入)
  • 绝不使用 ==strcmp() 做域名比对

密钥轮换时域名需重新加密,不能只更新密钥配置

很多团队以为改了配置里的密钥,旧数据就自动“升级”了——这是典型误解。加密是单向操作,旧密文只能用原密钥解密。若要轮换密钥:

  • 必须在应用层加一层兼容逻辑:先尝试用新密钥解密,失败则用旧密钥解密并立即用新密钥重加密存储
  • 数据库字段需预留足够长度(GCM 下约增加 40%),避免 varchar(255) 存不下新格式
  • 批量重加密任务必须加分布式锁,防止并发导致同一行被多次覆盖
  • 切勿在低峰期一次性全量更新——dns 解析、cdn 缓存、客户端 cookie 都可能让旧域名短暂回流

真正难的不是加密函数怎么写,而是让加密后的值在分布式、多版本、长期演进的系统里始终可逆、可验证、可迁移。

text=ZqhQzanResources