短链接服务的核心是将长链接映射为简短的字符串标识,用户访问短链接时再跳转回原始长链接。基础的短链接生成方案大多采用自增ID加进制转换的方式,这种逻辑很容易被逆向还原出原始ID,进而推断出长链接内容,存在隐私泄露风险。PHP作为常用的后端开发语言,在短链接系统中应用广泛,通过升级加密算法可以有效提升短链接的抗还原能力。

基础短链接方案的还原风险
常见的短链接生成逻辑是先给每个长链接分配一个自增的唯一ID,再将这个ID转换为62进制字符串作为短链接后缀。这种方式生成的短链接,只要拿到进制转换的规则,就可以很容易地将短字符串还原为原始ID,进而通过ID查询到对应的长链接。如果原始长链接包含用户隐私信息、内部接口地址等内容,就会被泄露。
下面是一个基础短链接生成的PHP代码示例,这种代码生成的短链接就存在明显的还原风险:
<?php
// 基础短链接生成示例,存在还原风险
function base62_encode($num) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$result = '';
while ($num > 0) {
$result = $chars[$num % 62] . $result;
$num = intval($num / 62);
}
return $result;
}
// 假设自增ID为123456
$short_code = base62_encode(123456);
echo $short_code; // 输出2Bj8
?>
PHP加密算法升级方案汇总
方案一:对称加密保护原始链接
可以将原始长链接先进行对称加密,再将加密后的字符串作为短链接的标识,这样即使拿到短字符串,没有加密密钥也无法还原出原始长链接。常用的对称加密算法有AES,PHP中可以通过openssl扩展实现。
下面是使用AES-256-CBC加密算法实现短链接的示例:
<?php
// 对称加密方案生成短链接
class ShortLinkEncrypt {
private $key; // 加密密钥
private $iv; // 初始化向量
public function __construct($key, $iv) {
$this->key = $key;
$this->iv = $iv;
}
// 生成短链接标识
public function generateShortCode($long_url) {
// 对长链接进行AES加密
$encrypted = openssl_encrypt($long_url, 'AES-256-CBC', $this->key, 0, $this->iv);
// 对加密结果进行base64编码,替换特殊字符适配URL
$short_code = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($encrypted));
return $short_code;
}
// 还原原始长链接
public function decodeLongUrl($short_code) {
// 还原base64编码
$base64_str = str_replace(['-', '_'], ['+', '/'], $short_code);
$encrypted = base64_decode($base64_str);
// 解密得到原始长链接
$long_url = openssl_decrypt($encrypted, 'AES-256-CBC', $this->key, 0, $this->iv);
return $long_url;
}
}
// 使用示例
$key = 'this_is_a_32bit_secret_key_123456'; // AES-256需要32位密钥
$iv = '1234567890123456'; // CBC模式需要16位IV
$encrypt_obj = new ShortLinkEncrypt($key, $iv);
$long_url = 'https://ipipp.com/user/profile?uid=1001&token=abc123';
$short_code = $encrypt_obj->generateShortCode($long_url);
echo '短链接标识:' . $short_code . PHP_EOL;
echo '还原后的长链接:' . $encrypt_obj->decodeLongUrl($short_code) . PHP_EOL;
?>
方案二:非对称加密提升安全性
如果需要更高的安全性,可以使用非对称加密算法,比如RSA。服务端保存私钥,加密时使用公钥对长链接信息加密生成短标识,只有拥有私钥的服务端才能解密还原长链接,即使短标识被截取,没有私钥也无法还原内容。
下面是RSA加密实现短链接的示例:
<?php
// 非对称加密方案生成短链接
class ShortLinkRsa {
private $public_key;
private $private_key;
public function __construct($public_key_path, $private_key_path) {
$this->public_key = file_get_contents($public_key_path);
$this->private_key = file_get_contents($private_key_path);
}
// 生成短链接标识,使用公钥加密
public function generateShortCode($long_url) {
openssl_public_encrypt($long_url, $encrypted, $this->public_key);
$short_code = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($encrypted));
return $short_code;
}
// 还原原始长链接,使用私钥解密
public function decodeLongUrl($short_code) {
$base64_str = str_replace(['-', '_'], ['+', '/'], $short_code);
$encrypted = base64_decode($base64_str);
openssl_private_decrypt($encrypted, $long_url, $this->private_key);
return $long_url;
}
}
// 注意:实际使用前需要先生成RSA公钥和私钥文件
// 使用示例
$public_key_path = '/path/to/public_key.pem';
$private_key_path = '/path/to/private_key.pem';
$rsa_obj = new ShortLinkRsa($public_key_path, $private_key_path);
$long_url = 'https://ipipp.com/order/detail?order_id=20240501&user_id=50';
$short_code = $rsa_obj->generateShortCode($long_url);
echo '短链接标识:' . $short_code . PHP_EOL;
echo '还原后的长链接:' . $rsa_obj->decodeLongUrl($short_code) . PHP_EOL;
?>
方案三:自定义混淆算法结合盐值
如果不想使用复杂的加密算法,也可以自定义混淆规则,结合随机盐值提升抗还原能力。比如在自增ID的基础上,拼接随机盐值,再进行自定义规则的字符替换和乱序,让短标识无法直接通过进制转换还原。
下面是自定义混淆算法的示例:
<?php
// 自定义混淆算法生成短链接
class ShortLinkCustom {
private $salt_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
private $replace_map = [];
public function __construct() {
// 初始化字符替换映射表,打乱基础62进制字符的对应关系
$base_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$shuffled = str_shuffle($base_chars);
for ($i = 0; $i < strlen($base_chars); $i++) {
$this->replace_map[$base_chars[$i]] = $shuffled[$i];
}
}
// 生成短链接标识
public function generateShortCode($id) {
// 生成2位随机盐值
$salt = substr(str_shuffle($this->salt_chars), 0, 2);
// 拼接ID和盐值
$raw = $id . $salt;
// 转换为62进制
$base62 = $this->toBase62($raw);
// 对字符进行替换混淆
$confused = '';
for ($i = 0; $i < strlen($base62); $i++) {
$confused .= $this->replace_map[$base62[$i]];
}
return $confused;
}
// 还原原始ID
public function decodeId($short_code) {
// 反向替换字符
$reverse_map = array_flip($this->replace_map);
$base62 = '';
for ($i = 0; $i < strlen($short_code); $i++) {
$base62 .= $reverse_map[$short_code[$i]];
}
// 从62进制还原为原始字符串
$raw = $this->fromBase62($base62);
// 去除盐值得到原始ID
$id = substr($raw, 0, -2);
return $id;
}
// 转换为62进制
private function toBase62($num) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$result = '';
while ($num > 0) {
$result = $chars[$num % 62] . $result;
$num = intval($num / 62);
}
return $result;
}
// 从62进制还原
private function fromBase62($str) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$num = 0;
for ($i = 0; $i < strlen($str); $i++) {
$num = $num * 62 + strpos($chars, $str[$i]);
}
return $num;
}
}
// 使用示例
$custom_obj = new ShortLinkCustom();
$id = 123456;
$short_code = $custom_obj->generateShortCode($id);
echo '短链接标识:' . $short_code . PHP_EOL;
echo '还原后的ID:' . $custom_obj->decodeId($short_code) . PHP_EOL;
?>
不同方案对比与选择建议
不同加密升级方案的适用场景和特性存在差异,开发者可以根据业务需求选择:
| 方案类型 | 安全性 | 性能 | 适用场景 |
|---|---|---|---|
| 对称加密方案 | 中等 | 高 | 普通业务短链接,需要平衡安全性和性能的场景 |
| 非对称加密方案 | 高 | 低 | 涉及敏感隐私信息的短链接,对安全性要求极高的场景 |
| 自定义混淆方案 | 较低 | 极高 | 短链接访问量极大,对性能要求高,且隐私敏感度较低的场景 |
在实际部署时,还可以结合多种方案,比如先对长链接进行对称加密,再对加密结果做自定义混淆,进一步提升短链接的抗还原能力,更好地保护用户隐私和原始链接信息安全。
注意事项
- 加密密钥和盐值需要妥善保管,避免泄露,否则加密方案会失效
- 短链接标识的长度需要控制在合理范围,避免过长影响传播
- 如果短链接需要长期有效,需要考虑密钥轮换机制,避免单一密钥长期使用带来风险
- 解密逻辑需要做异常处理,避免无效的短链接标识导致服务报错