PHP地址被盗用通常指站点的静态资源、接口地址等被非授权站点或用户直接调用,导致带宽浪费、资源泄露甚至数据安全风险。要解决这类问题,需要结合请求特征校验、权限控制、时效性验证等多种策略,从请求入口拦截非法访问。

一、验证请求来源:防盗链基础策略
盗用地址的请求通常会携带来源信息,通过校验HTTP请求头中的Referer字段,可以初步判断请求是否来自授权站点。不过要注意Referer可以被伪造,因此该策略适合作为基础防护,不能单独作为唯一验证手段。
实现逻辑:获取请求的Referer值,判断是否在允许的域名白名单中,不在则返回403禁止访问。
<?php
// 允许的请求来源域名白名单
$allowReferer = [
'www.yoursite.com',
'yoursite.com'
];
// 获取请求头中的Referer
$referer = $_SERVER['HTTP_REFERER'] ?? '';
// 如果Referer为空或者不在白名单中,返回403
if (empty($referer)) {
header('HTTP/1.1 403 Forbidden');
exit('Access Denied');
}
// 解析Referer的域名
$refererHost = parse_url($referer, PHP_URL_HOST);
if (!in_array($refererHost, $allowReferer)) {
header('HTTP/1.1 403 Forbidden');
exit('Access Denied');
}
// 验证通过,正常返回资源
// 这里可以写返回图片、文件等资源的逻辑
?>二、生成时效性访问令牌
给资源地址附加有时效性的令牌,只有携带合法令牌的请求才能访问资源,令牌过期后自动失效,能有效防止地址被长期盗用。令牌可以结合时间戳、资源标识、密钥生成,通过签名校验合法性。
实现步骤:1. 生成令牌时拼接资源ID、过期时间戳、密钥,计算签名;2. 请求时校验令牌签名、判断是否过期;3. 过期或签名错误则拒绝访问。
<?php
// 令牌生成密钥,建议存在配置文件里不要硬编码
$tokenSecret = 'your_secret_key_123456';
// 生成资源访问令牌的函数
function generateResourceToken($resourceId, $expireSeconds = 300) {
global $tokenSecret;
$expireTime = time() + $expireSeconds;
// 拼接签名字符串:资源ID+过期时间+密钥
$signStr = $resourceId . $expireTime . $tokenSecret;
$sign = md5($signStr);
// 返回令牌:资源ID_过期时间_签名
return $resourceId . '_' . $expireTime . '_' . $sign;
}
// 校验资源访问令牌的函数
function verifyResourceToken($token) {
global $tokenSecret;
// 拆分令牌
$tokenArr = explode('_', $token);
if (count($tokenArr) != 3) {
return false;
}
list($resourceId, $expireTime, $sign) = $tokenArr;
// 校验是否过期
if (time() > $expireTime) {
return false;
}
// 重新计算签名校验
$checkSign = md5($resourceId . $expireTime . $tokenSecret);
if ($checkSign != $sign) {
return false;
}
return $resourceId;
}
// 使用示例:访问资源时校验令牌
$token = $_GET['token'] ?? '';
$resourceId = verifyResourceToken($token);
if (!$resourceId) {
header('HTTP/1.1 403 Forbidden');
exit('Token Invalid Or Expired');
}
// 令牌校验通过,返回对应资源
echo 'Resource ' . $resourceId . ' content';
?>三、限制请求频率与IP访问控制
盗用地址的请求通常会有较高的请求频率,结合请求频率限制和IP黑名单,可以进一步拦截批量盗用的行为。可以使用Redis记录IP的请求次数,超过阈值则暂时封禁。
<?php
// 连接Redis,需要提前安装Redis扩展并启动Redis服务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$clientIp = $_SERVER['REMOTE_ADDR'];
// 每个IP每分钟最多允许10次请求,可根据资源类型调整
$limit = 10;
$expire = 60;
// 获取当前IP的请求次数
$requestCount = $redis->get('request_limit:' . $clientIp);
if ($requestCount >= $limit) {
header('HTTP/1.1 403 Forbidden');
exit('Request Too Frequent');
}
// 计数递增,第一次访问设置过期时间
if (!$requestCount) {
$redis->set('request_limit:' . $clientIp, 1, $expire);
} else {
$redis->incr('request_limit:' . $clientIp);
}
// 频率校验通过,继续后续逻辑
?>四、结合用户身份校验
如果资源仅对登录用户开放,还可以在地址访问时校验用户登录状态,未登录用户直接拒绝访问。可以结合Session或者JWT令牌校验用户身份。
<?php
session_start();
// 校验用户是否登录
if (!isset($_SESSION['user_id']) || empty($_SESSION['user_id'])) {
header('HTTP/1.1 401 Unauthorized');
exit('Please Login First');
}
// 登录用户校验通过,返回资源
?>五、策略组合建议
单一防护策略容易被绕过,建议根据实际场景组合使用:公开资源可以组合Referer校验+时效性令牌+频率限制;私有资源可以额外加上用户身份校验。同时要注意定期更新密钥、调整频率阈值,避免误拦截正常用户请求。
| 防护策略 | 适用场景 | 防护强度 |
|---|---|---|
| Referer校验 | 公开静态资源 | 低 |
| 时效性令牌 | 所有资源地址 | 中 |
| 频率限制+IP封禁 | 高访问量资源 | 中 |
| 用户身份校验 | 私有付费资源 | 高 |
以上策略可以根据站点需求灵活调整,核心思路是让盗用者无法获取长期有效的访问地址,同时尽可能降低对正常用户的影响。