服务热线
1888888888
作者:文煞发布时间:2024-06-13分类:PHP笔记浏览:5136
为什么要屏蔽部分访问,相信大部分站长都没有注意查看网站日志,为什么每天会产生几M甚至几十M的网站日志,这是因为我们的web服务器(nginx或者apcha)会为每一个http或者https请求记录下来,日志内容一般包括访问者的IP、UA、请求的URL资源和来源URL、请求方式、返回状态、传输的参数等。通常我们通过分析网站日志可以分辨出是否存在危险或者恶意访问。当我们发现一些非正常的网站的时候,可以通过一些工具进行限制,宝塔面板就有对应的工具,收费也不高,但是你实在不想为此花钱,那么可以从PHP脚本下手,做一些比较简单的限制工作。
我们来分析一段通过我原创开发的zblog网站日志插件的记录:
整整连续10条记录都是同IP对网站进行了恶意访问,间隔时间如此之短,请求的资源都不存在。据我分析,该访问者希望获取我网站文件的压缩文件,希望通过抓取压缩包的方式获取我的网站源码、其他资源,如果能够成功下载网站文件的压缩包,就可以从源码中得到mysql数据库账号信息,从而控制我的数据库。所以,如果大家通过压缩的方式对网站进行了备份,一定要及时删除备份文件。避免对网站数据泄露,造成不可想象的损失。
既然我们已经知道该用户是恶意访问,那么我们应该如何通过PHP脚本进行限制以保护网站的安全呢?我为大家整理出了如下思路:
为什么要提cookie限制访问呢?我可以只允许支持cookie的用户进行访问,大部分用户如果通过正常浏览器进行访问,基本都是支持cookie的,除非用户关闭了浏览器的cookie功能。我个人理解很多机器访问是不会像浏览器一样支持cookie的,从而达到限制异常访问的目的,不过该功能可能会对部分搜索引擎蜘蛛的抓取造成影响,所以我们需要提前进行甄别,我在前面的文章介绍过PHP如何识别蜘蛛,所以这里就不过多介绍了。同时访问者可以通过模拟真实用户传递cookie参数而对我们的判断进行欺骗,甚至他可能本身就是利用浏览器来进行访问的,比如部分采集工具就是调用浏览器来进行内容抓取的。显然该功能只能屏蔽部分异常访问,不过我们可以增加cookie的模拟难度来增加识别准确度。
function checkcookie($str=null) { $return = false; if($str == 0 || $str == null) { $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $cookiename = ''; $cookievalue = ''; for ($i = 0; $i < 8; $i++) { $cookiename .= $characters[mt_rand(0, strlen($characters) - 1)]; } for ($i = 0; $i < 16; $i++) { $cookievalue .= $characters[mt_rand(0, strlen($characters) - 1)]; } setCookie($cookiename, $cookievalue, 5 ,'/', '', true, true); } if (isset($_COOKIE["$cookiename"]) && $cookievalue == $_COOKIE["$cookiename"]) { $return = true; } return $return; }
该代码设置了一个随机的cookie 8位字符的键名和一个随机16位字符的对应值。我们再通过获取该cookie的值来对用户浏览器是否支持cookie进行判断。如果支持则checkcookie()返回true,否则返回false。虽然该方法并不是十分准确,但是也可以作为我们的一个判断依据。使用方法:
<?php if(checkcookie() == false){ die('您的浏览器不支持cookie'); } ?>
if (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false) { //可能是真实浏览器 }else{ die('坚决杜绝一切非正常访问'); }
一般来说,如果浏览器不支持text/html,基本可以判断为非真实用户进行访问!
这里可以使用session来储存用户的访问时间,对两次访问的时间进行对比,如果间隔时间小于1秒,也可以进本判断为非正常访问。那么代码应该怎么写呢?
<?php session_start(); // 启动会话 //先判断用户是不是访问过,如果没有访问过, 设置会话变量 if(!isset($_SESSION['time'])){ $_SESSION['time'] = time(); }else{ $usertime = time - $_SESSION['time'];//计算两次的访问时间差 if($usertime <= 1){//如果时间差小于1秒,则退出脚本或者禁止访问 die('禁止频繁访问'); } } ?>
如果我已知一些IP属于非正常访问,就像我上面截图中的访问行为,我百分百确定它是非正常访问!那么我可以通过判断IP进行访问限制:
<?php $ips = ['127.0.00.1','192.168.1.1'];//限制访问的IP foreach($ips as $ip){ if($ip == $_SERVER['REMOTE_ADDR']){ die('该IP已被禁止访问'); } } ?>
根据一些模拟访问的UA头部信息特征进行限制,这里我们可以简单举个例子。下图中可以看出右侧的UA头部信息,然后分析它在网站上的操作,访问了一些不存在的页面,截图中看到返回的状态码是503,这是我根据IP和UA信息判断为非正常访问,特意反馈到浏览器的。
<?php $ua = $_SERVER['HTTP_USER_AGENT']; //限制UA信息为空的访问 if($ua == null){ die('访问异常,页面禁止加载') } //限制带有特定UA特征的访问 $array = ['Dalvik/2.1.0','Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)']; foreach($array as $v){ if(strpos($ua, $v) >0 || $ua == $v){//判断用户的UA头部信息是否包含禁止的UA特征或者等于禁止的UA die('访问异常,页面禁止加载') } } ?>
以上介绍的都是一些禁止异常访问的思路,虽然不能准却识别异常访问,但是大部分简单的模拟访问、机器访问可以通过上面的这些方法进行识别并加以限制,以提高网站被暴力破解、异常请求所带来的一些安全威胁。如果你想要提供识别异常访问的准确度,你可以使用专业的第三方库来进行识别。本文中介绍的die()函数用于停止脚本继续执行,当然在禁止脚本运行之前,我们可以自定义一些状态码告诉浏览器我们想让它理解的一些信息。比如:
<?php // 设置自定义状态码 http_response_code(403); // 发送自定义头部信息 header('X-Custom-Status: Forbidden'); // 结束脚本执行 exit('对不起,您无权访问该资源。'); ?>
案例代码中发送了一个404状态,你也可以设置其他状态码,比如500,400,300等。
分享:
支付宝
微信