PHP带时效性的字符串加解密函数实现

听雨眠
听雨眠
发布时间:2026-10-16 | 3人浏览过
原创

在Web开发中,常需对敏感信息进行临时加密,如SSO Token或动态密码。本方案提供了一款PHP函数,能在指定秒数内完成字符串的加密与还原。若超出有效期,解密将直接返回空值。核心逻辑结合了密钥派生、伪随机混淆及时间戳哈希校验,兼顾了安全性与易用性。

加密原理解析

该函数并非仅依赖简单的Base64编码,而是构建了一套完整的加解密流程,主要包含以下关键点:

  • 密钥处理:主密钥经过MD5摘要后拆分为$keya和$keyb,分别用于初始向量构造和内容校验,降低主密钥泄露风险。
  • 随机前缀:每次加密时加入由当前微时间生成的$ckey_length位随机字符串,使得即使原文和密钥完全相同,密文也会变化,增加暴力破解难度。
  • 时间戳绑定:加密时将Unix时间戳(补全至10位)置于密文头部。解密时先比对当前时间与头部时间戳,若超过设定$expiry,则拒绝还原。
  • 完整性校验:正文前插入16位的MD5哈希值(由原文+副密钥生成)。解密成功与否不仅取决于能否正确逆向算法,还取决于哈希校验是否匹配,防止密文被篡改。

参数与使用方法

函数签名如下,支持两种操作模式:

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 3600)

参数说明:

  • $string:待处理的原始字符串或已编码的密文。
  • $operation:操作类型。ENCODE为加密,DECODE为解密(默认)。
  • $key:加解密密钥。建议设置为固定常量或从配置中心读取。
  • $expiry:有效期(秒)。设为0表示永久有效,大于0则表示相对当前时间的存活时长。

第1步:生成带时效的加密串

在用户登录或需要颁发临时凭证时调用加密函数,限制其有效期。

// 加密内容 'abc',使用密钥 'my_secret_key',有效期 3600 秒 (1小时)
$encrypted = authcode('abc', 'ENCODE', 'my_secret_key', 3600);
echo "加密结果: " . $encrypted;

此时获取的$encrypted即为密文,可安全传输给前端或存储在Cookie中。

第2步:在有效期内还原明文

在处理请求时,使用相同的密钥尝试解密。

// 传入密文,操作设为 DECODE
$decrypted = authcode($encrypted, 'DECODE', 'my_secret_key');

if ($decrypted === 'abc') {
    echo "解密成功:" . $decrypted;
} else {
    echo "解密失败或已过期";
}

只要在当前时间戳之后的3600秒内执行此步骤,即可准确还原出'abc'。

第3步:验证超时失效机制

模拟过期场景,延时后再次请求解密,观察返回结果。

// 假设等待超过 3600 秒...
// 再次解密
$expired_result = authcode($encrypted, 'DECODE', 'my_secret_key');

if ($expired_result === '') {
    echo "令牌已过期,拒绝访问";
}

由于内部逻辑检测到了头部时间戳与当前时间差值超出了$expiry的限制,函数会直接返回空字符串'',从而达到自动过期的目的。

完整代码实现

以下为完整的authcode函数定义,可直接嵌入项目中使用。该逻辑参考了经典社区框架的实现方式,具有较高的稳定性。

			/**
 * @param string $string 原文或者密文
 * @param string $operation 操作(ENCODE | DECODE), 默认为 DECODE
 * @param string $key 密钥
 * @param int $expiry 密文有效期, 加密时候有效, 单位 秒,0 为永久有效
 * @return string 处理后的 原文或者 经过 base64_encode 处理后的密文
 */
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 3600) {
    $ckey_length = 4; // 随机密钥长度
    
    // 密钥派生:区分主密钥副密钥
    $key = md5($key ? $key : 'DEFAULT_KEY_VALUE'); // 此处替换为你的实际KEY获取逻辑
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    
    // 初始化控制数组:解密取前缀,加密取随机微时间后缀
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);
    
    // 组装待加密字符串:[10位时间戳] + [16位校验哈希] + [原文]
    // 解密时则去掉前缀ckey_length,进行base64解码
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);
    
    // RC4-like 流密码核心循环
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    
    for($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    
    for($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    
    for($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    
    if($operation == 'DECODE') {
        // 验证:1. 时间戳合法 (且未过期)
        // 2. 内容哈希合法 (防止中间人篡改)
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        return $keyc.str_replace('=', '', base64_encode($result));
    }
}

注意事项

  1. 环境一致性:加解密双方(如服务端A发送,服务端B接收)必须保持$key一致,否则无法还原。
  2. 性能考量:该算法在PHP环境中运行效率较高,但若处理极大体积文本,建议分块处理或改用AES等更高级别加密标准。
  3. 密钥管理:$key参数务必硬编码或在环境变量中严格保护,切勿在日志或前端暴露。

以上就是带时间限制的PHP字符串加密函数的详细内容,更多关于PHP安全开发的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表