在php项目开发中,URL参数直接拼接敏感信息比如用户ID、订单编号时,很容易被篡改或窃取,因此对URL参数进行加密是提升安全性的常见操作。php本身提供了基础的base64编码能力,同时也可以通过自定义算法实现更安全的加密逻辑。
base64编码处理URL参数
base64是php内置的编码方式,虽然不是严格意义上的加密,但可以把参数转换为不可直接识别的字符串,适合非敏感场景的参数处理。不过标准base64编码结果包含+、/、=等字符,在URL中传递时容易出现解析问题,需要做URL安全替换。
base64编码URL参数的实现
编码时先对参数做base64编码,再把URL不安全的字符替换为安全字符,解码时反向操作即可。
<?php
// base64编码URL参数
function base64_url_encode($data) {
// 标准base64编码
$base64 = base64_encode($data);
// 替换URL不安全字符,+替换为-,/替换为_,去掉末尾的=
$safe_base64 = str_replace(['+', '/', '='], ['-', '_', ''], $base64);
return $safe_base64;
}
// base64解码URL参数
function base64_url_decode($safe_base64) {
// 反向替换字符,补全=号
$base64 = str_replace(['-', '_'], ['+', '/'], $safe_base64);
// 计算需要补的=号数量
$pad_len = 4 - strlen($base64) % 4;
if ($pad_len < 4) {
$base64 .= str_repeat('=', $pad_len);
}
// 解码返回
return base64_decode($base64);
}
// 使用示例
$origin_param = "user_id=123&order_id=456";
$encoded = base64_url_encode($origin_param);
echo "编码后参数:" . $encoded . "<br>";
$decoded = base64_url_decode($encoded);
echo "解码后参数:" . $decoded;
?>
base64方式的注意事项
这种方式本质是编码不是加密,任何人拿到编码后的字符串都可以反向解码得到原始参数,因此不能用于加密密码、支付信息等敏感内容,只适合做参数的简单混淆。
自定义加密解密实现URL参数加密
如果需要更高的安全性,可以自定义加密算法,结合密钥对参数进行加密,只有持有密钥的服务才能解密,适合敏感参数的传输场景。
自定义简单加密算法实现
这里使用异或运算结合密钥的方式实现简单加密,异或运算的特点是同一个密钥异或两次可以还原原始数据,实现简单且效率较高。
<?php
// 自定义加密函数,key为加密密钥
function custom_encrypt($data, $key) {
$result = '';
$key_len = strlen($key);
// 遍历数据的每个字符,和密钥对应字符做异或运算
for ($i = 0; $i < strlen($data); $i++) {
$char = $data[$i];
$key_char = $key[$i % $key_len];
$result .= chr(ord($char) ^ ord($key_char));
}
// 对加密结果做base64 URL安全编码,方便URL传递
return base64_url_encode($result);
}
// 自定义解密函数,key需要和加密时的密钥一致
function custom_decrypt($encrypted_data, $key) {
// 先解码base64 URL安全字符串,得到加密后的原始二进制数据
$encrypted = base64_url_decode($encrypted_data);
$result = '';
$key_len = strlen($key);
// 反向异或运算还原原始数据
for ($i = 0; $i < strlen($encrypted); $i++) {
$char = $encrypted[$i];
$key_char = $key[$i % $key_len];
$result .= chr(ord($char) ^ ord($key_char));
}
return $result;
}
// 复用之前的base64 URL安全编解码函数
function base64_url_encode($data) {
$base64 = base64_encode($data);
$safe_base64 = str_replace(['+', '/', '='], ['-', '_', ''], $base64);
return $safe_base64;
}
function base64_url_decode($safe_base64) {
$base64 = str_replace(['-', '_'], ['+', '/'], $safe_base64);
$pad_len = 4 - strlen($base64) % 4;
if ($pad_len < 4) {
$base64 .= str_repeat('=', $pad_len);
}
return base64_decode($base64);
}
// 使用示例
$secret_key = "my_secret_key_2024"; // 实际使用中密钥需要妥善保管,不要硬编码在代码中
$origin_param = "user_id=123&pay_amount=99.9";
$encrypted = custom_encrypt($origin_param, $secret_key);
echo "加密后参数:" . $encrypted . "<br>";
$decrypted = custom_decrypt($encrypted, $secret_key);
echo "解密后参数:" . $decrypted;
?>
自定义加密的优化建议
- 密钥不要硬编码在代码里,可以放在环境变量或者配置文件中,避免密钥泄露导致加密失效
- 如果参数长度较长,可以结合分段加密或者更成熟的加密算法比如AES,异或算法适合简单场景,复杂场景建议使用php的openssl扩展实现AES加密
- 加密后的参数可以设置过期时间,在解密时校验时间戳,避免参数被长期盗用
两种方式的对比选择
| 方式 | 安全性 | 实现难度 | 适用场景 |
|---|---|---|---|
| base64编码 | 低,仅为混淆 | 简单,内置函数支持 | 非敏感参数,只需要避免参数直接可见的场景 |
| 自定义加密 | 较高,依赖密钥安全性 | 中等,需要自定义算法逻辑 | 敏感参数传输,需要防止参数被篡改或解密的场景 |
在实际开发中,需要根据参数的敏感程度选择合适的方案,敏感场景建议优先使用成熟的加密扩展比如openssl实现AES加密,安全性更有保障。