在PHP项目中,地址访问限制是提升站点安全性的常用手段,主要通过对请求来源、访问路径等信息的校验,拦截不符合规则的请求。常见的限制场景包括仅允许特定IP访问后台、禁止非指定域名调用接口、限制特定路径的访问权限等。

基于IP地址的访问限制
IP限制是最基础的地址限制方式,通过获取客户端的IP地址,判断是否在允许或禁止的列表中。PHP中可以通过$_SERVER['REMOTE_ADDR']获取客户端IP,部分代理环境下可能需要结合$_SERVER['HTTP_X_FORWARDED_FOR']获取真实IP,但要注意该字段可被伪造,高安全场景需额外校验。
以下是一个简单的IP白名单限制示例:
<?php
// 允许访问的IP白名单
$allowIpList = ['127.0.0.1', '192.168.0.1', '10.0.0.5'];
// 获取客户端IP
$clientIp = $_SERVER['REMOTE_ADDR'];
// 判断IP是否在白名单中
if (!in_array($clientIp, $allowIpList)) {
header('HTTP/1.1 403 Forbidden');
echo '当前IP无访问权限';
exit;
}
// 后续正常业务逻辑
echo '欢迎访问,IP校验通过';
?>基于请求来源域名的限制
如果需要限制接口仅允许特定域名调用,可以通过校验请求头中的HTTP_REFERER字段实现,该字段记录了请求的来源页面地址。注意该字段同样可被伪造,仅适合低安全级别的场景使用。
域名限制的实现示例如下:
<?php
// 允许访问的来源域名
$allowRefererList = ['https://ipipp.com', 'https://www.ipipp.com'];
// 获取请求来源
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
// 解析来源域名
$refererHost = '';
if (!empty($referer)) {
$parseResult = parse_url($referer);
$refererHost = isset($parseResult['host']) ? $parseResult['host'] : '';
}
// 校验域名
if (!in_array($refererHost, $allowRefererList)) {
header('HTTP/1.1 403 Forbidden');
echo '非法请求来源';
exit;
}
// 后续接口逻辑
echo '请求来源校验通过';
?>基于访问路径的规则限制
针对特定路径的访问限制,可以结合请求的URI进行判断,比如限制/admin路径仅允许内网IP访问,其他路径不做限制。这种方式可以灵活适配不同页面的权限要求。
路径限制的实现示例如下:
<?php
// 获取请求路径
$requestUri = $_SERVER['REQUEST_URI'];
// 定义需要限制的路径前缀
$limitPathPrefix = '/admin';
// 判断当前路径是否需要限制
if (strpos($requestUri, $limitPathPrefix) === 0) {
// 限制/admin路径仅允许内网IP访问
$clientIp = $_SERVER['REMOTE_ADDR'];
$innerIpPrefixList = ['192.168.', '10.', '127.'];
$isInnerIp = false;
foreach ($innerIpPrefixList as $prefix) {
if (strpos($clientIp, $prefix) === 0) {
$isInnerIp = true;
break;
}
}
if (!$isInnerIp) {
header('HTTP/1.1 403 Forbidden');
echo '该路径仅允许内网访问';
exit;
}
}
// 后续业务逻辑
echo '路径访问校验通过';
?>规则设置的注意事项
在实际设置地址访问限制规则时,需要注意以下几点:
- 高安全场景不要仅依赖
HTTP_X_FORWARDED_FOR和HTTP_REFERER字段,这两个字段都可由客户端伪造,建议结合服务端会话或者签名校验提升安全性。 - IP限制规则建议支持CIDR格式,比如允许192.168.0.0/24整个网段访问,方便批量管理IP权限。
- 限制规则触发后,除了返回403状态码,也可以记录访问日志,方便后续排查恶意请求。
- 如果是分布式部署的项目,获取客户端IP时要考虑负载均衡转发的场景,避免获取到负载均衡的IP而非真实客户端IP。
通用限制规则封装示例
为了方便复用,可以将地址限制逻辑封装成通用函数,适配不同的限制需求:
<?php
/**
* 地址访问限制校验函数
* @param array $ipWhiteList IP白名单,支持单个IP和CIDR格式
* @param array $pathLimitList 路径限制规则,格式为['路径前缀' => ['允许的IP列表']]
* @return bool 校验通过返回true,否则直接输出错误并退出
*/
function checkAccessLimit($ipWhiteList = [], $pathLimitList = []) {
$clientIp = $_SERVER['REMOTE_ADDR'];
$requestUri = $_SERVER['REQUEST_URI'];
// 先校验全局IP白名单
if (!empty($ipWhiteList)) {
$ipPass = false;
foreach ($ipWhiteList as $allowIp) {
// 处理CIDR格式IP
if (strpos($allowIp, '/') !== false) {
list($subnet, $mask) = explode('/', $allowIp);
$clientIpLong = ip2long($clientIp);
$subnetLong = ip2long($subnet);
$maskLong = ~((1 << (32 - $mask)) - 1);
if (($clientIpLong & $maskLong) === ($subnetLong & $maskLong)) {
$ipPass = true;
break;
}
} else {
if ($clientIp === $allowIp) {
$ipPass = true;
break;
}
}
}
if (!$ipPass) {
header('HTTP/1.1 403 Forbidden');
echo 'IP不在允许列表中';
exit;
}
}
// 再校验路径限制规则
foreach ($pathLimitList as $pathPrefix => $allowIpList) {
if (strpos($requestUri, $pathPrefix) === 0) {
if (!in_array($clientIp, $allowIpList)) {
header('HTTP/1.1 403 Forbidden');
echo '该路径无访问权限';
exit;
}
}
}
return true;
}
// 使用示例
$ipWhiteList = ['127.0.0.1', '192.168.0.0/24'];
$pathLimitList = ['/admin' => ['127.0.0.1', '192.168.0.1']];
checkAccessLimit($ipWhiteList, $pathLimitList);
// 校验通过后执行后续逻辑
echo '访问校验全部通过';
?>