使用IP地址设置用户白名单
为什么要设置白名单
一些api接口不可能对所有人都开放,比如一些比较敏感的接口就需要对ip地址访问做一些限制。比如从A域名使用ajax请求B域名的接口服务,就有必要将A域名IP加入B域名的白名单中。比如本例类中就要实现2种白名单服务,一:针对用户客户端ip地址的白名单,获取用户客户端IP地址,然后判断用户IP是否在白名单内;二:针对服务器域名ip地址的白名单,获取用户操作网页所在服务器域名,并根据域名得到服务器ip地址,再判断该服务器ip地址是否在白名单内。
实现一个白名单简单类
class Whitelist {
private $allowIp;
public function __construct($allow)
{
$this->allowIp = $allow;
}
// 检查用户客户端的ip地址是否在白名单内
public function checkAllowIp()
{
$ip = $this->getIp();
if (!in_array($ip, $this->allowIp)) {
return false;
} else {
return true;
}
}
/**
* 获取客户端访问ip
*/
private function getIp()
{
if (getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
} else if (getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} else if (getenv('REMOTE_ADDR')) {
$ip = getenv('REMOTE_ADDR');
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
$ips = explode(',', $ip);
if (count($ips) > 1) {
$ip = $ips[0];
}
return $ip;
}
// 检查发送请求的服务器ip
public function checkServerIp()
{
$ip = $this->getIpByUrl();
// 查看IP地址是否在白名单内
if (!in_array($ip, $this->allowIp)) {
return false;
} else {
return true;
}
}
// 根据发送域名获取ip地址
private function getIpByUrl()
{
// 获取发起请求的域名
if (!isset($_SERVER['HTTP_ORIGIN'])) {
return false;
}
$originUrl = $_SERVER['HTTP_ORIGIN'];
// 获取POST提交的服务器的域名
$originHost = explode('//', $originUrl)[1];
// 获取域名所属的ip地址
try {
// 根据域名信息获取到域名对应的ip地址
$dns = dns_get_record($originHost, DNS_A);
if(count($dns) <= 0) {
return false;
}
return $dns[0]['ip'];
} catch(Exception $err) {
return false;
}
}
}
类的应用
$allowIp = [
'1.126.98.145',
'124.6.232.187',
...
];
// 实例化一个类
$white = new Whitelist($allowIp);
// 根据发送ajax请求的服务器的域名得到其ip地址
// 判断该ip地址是否在白名单内
if(!$white->checkServerIp()) {
$res = [
'code' => 3,
'msg' => '抱歉,您的权限受到了限制'
];
$json = json_encode($res, JSON_UNESCAPED_UNICODE);
exit($json);
}
// 直接检查用户客户端的Ip地址是否在白名单内
if(!$white->checkAllowIp()) {
...
}
HTTP_REFERER和HTTP_ORIGIN
我们在脚本中打印$_SERVER['HTTP_ORIGIN']
和$_SERVER['HTTP_REFERER']
可以看到只有是POST或者GET方法的时候,$_SERVER中才会有这两项。我们来看一下百度的解释:
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的
origin作用于referer类似,主要是用来说明最初请求是从哪里发起的。通常这两个值都是相同的。但是,origin只用于Post请求,而Referer则用于所有类型的请求;所以origin的方式比Referer更安全点吧。