PHP代码,拒绝频繁访问

一个网站性能有限,如果有人恶意去频繁对页面进行刷新,其实对服务器影响是很大的,导致资源使用非常高,直接影响到其他用户的体验。

那么对于这样的一些频繁访问,我们该如何去拒绝它呢?

我总结了两种方法:第一种方式通过Web服务器检查拒绝,第二种方式通过代码进行拦截过滤

通过Web服务器检查拒绝

第一种方式大致原理和思路是这样的,比如我们的Web服务器采用Nginx,那个Nginx可以记录用户访问记录,并通过查询分析这个日志可以得出频繁访问用户IP列表。

我们需要做的事情:

做一个定时任务,定时去分析日志文件,将得到的频繁访问用户的IP,并将IP设置到Nginx配置文件中的IP黑名单中,然后进行reload配置文件,当IP类表较大时,可以更新到iptables中去。

日志文件,查询IP的访问次数

[[email protected] www]# grep ‘195.154.216.165‘ 2015-11-28.access.log|wc -l

289

[[email protected]-dig www]#
 1 [[email protected] www]# curl ipinfo.io/195.154.216.165;echo‘‘
 2 {
 3   "ip": "195.154.216.165",
 4   "hostname": "fr.07.gs",
 5   "city": "",
 6   "region": "",
 7   "country": "FR",
 8   "loc": "48.8600,2.3500",
 9   "org": "AS12876 ONLINE S.A.S."
10 }
11 [[email protected] www]# 

Nginx 上,所以可以使用 Nginx 的 Deny 来拒绝攻击者的IP访问。

 1 deny 195.154.211.220;
 2 deny 195.154.188.28;
 3 deny 195.154.188.186;
 4 deny 180.97.106.161;
 5 deny 180.97.106.162;
 6 deny 180.97.106.36;
 7 deny 195.154.180.69;
 8 deny 195.154.211.26;
 9 deny 221.229.166.247;
10 deny 180.97.106.37;
11 deny 195.154.216.164;
12 deny 195.154.216.165;
13 [[email protected] website]# 

通过代码进行拦截过滤

 1 $config[‘request_limit‘][‘open‘] = true; // 开启拦截请求
 2 $config[‘request_limit‘][‘all_request‘] = false; // 拦截所有请求,否则拦截相同请求
 3 $config[‘request_limit‘][‘min_request_interval_time‘] = 10;   // 允许的最小请求间隔 单位S(秒)
 4 $config[‘request_limit‘][‘max_malicious_times‘] = 1;  // 允许的最大恶意请求次数
 5
 6 function maliciousRequestInterceptor() {
 7     $config = array(
 8         ‘all_request‘=> false,
 9         ‘min_request_interval_time‘ => 1,
10         ‘max_malicious_times‘ => 10
11     );
12     $request_limit_cfg = C("request_limit");
13     if($request_limit_cfg && is_array($request_limit_cfg)){
14         if($request_limit_cfg[‘open‘] == false){
15             return true;
16         }
17         $config = array_merge($config,$request_limit_cfg);
18     }
19     session_start();
20     $pre_request_url = $_SESSION[‘PRE_REQUEST_URL‘];
21     $pre_request_time = $_SESSION[‘PRE_REQUEST_TIME‘];
22     $cur_request_url = GetCurUrl();
23     if(isset($pre_request_url) && isset($pre_request_time)){
24         if((trim($pre_request_url) == trim($cur_request_url) || $config[‘all_request‘])
25                 && (((microtime(TRUE) - floatval($pre_request_time))) < floatval($config[‘min_request_interval_time‘]))){
26             $request_times = $_SESSION[‘MALICIOUS_REQUEST_TIMES‘];
27             if(isset($request_times)){
28                 $request_times = intval($request_times) + 1;
29             }else{
30                 $request_times = 1;
31             }
32             $_SESSION[‘MALICIOUS_REQUEST_TIMES‘] = $request_times;
33             if ($request_times > $config[‘max_malicious_times‘]) {
34 //                    error_log("intercept a malicious request ".$_SERVER[‘REMOTE_ADDR‘].":".$cur_request_url);
35 //                    header($_SERVER["SERVER_PROTOCOL"]." 403 access denied.");
36 //                    exit();
37                 return false;
38             }
39         }else{
40             $_SESSION[‘MALICIOUS_REQUEST_TIMES‘] = 0;
41         }
42     }
43     $_SESSION[‘PRE_REQUEST_URL‘] = $cur_request_url;
44     $_SESSION[‘PRE_REQUEST_TIME‘] = microtime(TRUE);
45     return true;
46 }
47 // php获取当前访问的完整url地址
48 function GetCurUrl() {
49     $url = ‘http://‘;
50     if (isset ( $_SERVER [‘HTTPS‘] ) && $_SERVER [‘HTTPS‘] == ‘on‘) {
51         $url = ‘https://‘;
52     }
53     if ($_SERVER [‘SERVER_PORT‘] != ‘80‘) {
54         $url .= $_SERVER [‘HTTP_HOST‘] . ‘:‘ . $_SERVER [‘SERVER_PORT‘] . $_SERVER [‘REQUEST_URI‘];
55     } else {
56         $url .= $_SERVER [‘HTTP_HOST‘] . $_SERVER [‘REQUEST_URI‘];
57     }
58     return $url;
59 }
时间: 2024-10-11 20:31:07

PHP代码,拒绝频繁访问的相关文章

PHP禁止同一IP频繁访问以防止网站被防攻击或采集的代码

<?php /* *通过禁止IP频繁访问防止网站被防攻击代码*design by www.scutephp.com*/header('Content-type: text/html; charset=utf-8');$ip=$_SERVER['REMOTE_ADDR'];//获取当前访问者的ip$logFilePath='./log/';//日志记录文件保存目录$fileht='.htaccess2';//被禁止的ip记录文件$allowtime=60;//防刷新时间$allownum=5;//

如何从python代码中直接访问Android的Service

在Kivy中,通过pyjnius扩展可以间接调用Java代码,而pyjnius利用的是Java的反射机制.但是在Python对象和Java对象中转来转去总让人感觉到十分别扭.好在android提供了binder这个进程间通信的功能,Java中的Service也是基于Binder的C++代码封装来实现进程间通信的,这也为从Python代码中绕开pyjnius直接访问Java代码提供了可能,既然Java的Service是基于C++的封装来实现的,也同样可以在Python中封装同样的C++代码,这篇文

Nginx 防CC攻击拒绝代理访问

先大概说说简单的结构…前端一个Nginx反向代理,后端一个Nginx instance app for PHP…实际上就是个Discuz,之前面对CC攻击都是预警脚本或者走CDN,但是这次攻击者不再打流量,而是针对数据库请求页面进行攻击,如search操作…帖子ID F5等..从日志分析来看是从3个URL着手攻击的,当时使用Nginx 匹配$query_string 来return 503…不过会导致页面不能访问,所以想到这么一个折中的办法. 首先你看一段代理请求的NGINX日志: ##通过分析

手机Web网站,设置拒绝电脑访问

最近一段时间,都在使用Jquery-Mobile + MVC做手机Web,有一些心得.体会 下面介绍如何拒绝电脑访问手机网站 电脑的浏览器,跟手机的浏览器内核不一样,这是我设置拒绝访问的思路. 下面是我已经封装好了的一个拒绝访问的一个方法 1 public static class IsMobileDevice 2 { 3 /// <summary> 4 /// 是否为手机访问 5 /// </summary> 6 /// <param name="strUserA

Kivy A to Z -- 如何从python代码中直接访问Android的Service

在Kivy中,通过pyjnius扩展可以间接调用Java代码,而pyjnius利用的是Java的反射机制.但是在Python对象和Java对象中转来转去总让人感觉到十分别扭.好在android提供了binder这个进程间通信的功能,Java中的Service也是基于Binder的C++代码封装来实现进程间通信的,这也为从Python代码中绕开pyjnius直接访问Java代码提供了可能,既然Java的Service是基于C++的封装来实现的,也同样可以在Python中封装同样的C++代码,这篇文

shiro之redis频繁访问问题

目前安全框架shiro使用较为广泛,其功能也比较强大.为了分布式session共享,通常的做法是将session存储在redis中,实现多个节点获取同一个session.此实现可以实现session共享,但session的特点是内存存储,就是为了高速频繁访问,每个请求都必须验证session是否存在是否过期,也从session中获取数据.这样导致一个页面刷新过程中的数十个请求会同时访问redis,在几毫秒内同时操作session的获取,修改,更新,保存,删除等操作,从而造成redis的并发量飙升

关于在事件代码中如何访问类中的变量

事件代码访问类中变量的3种方法. 在写事件代码的时候,常常需要引用主类中的变量.要访问这些变量是需要一些技巧的. 方法一: 加上final修饰符. 1 public class HelloWorld5 { 2 public static void main(String[] args) { 3 // 在变量前加上final,否则在事件代码里不能引用. 4 final String str = "孔肖寒"; 5 6 Display display = Display.getDefault

【C#代码】C#访问域示例

开发原因: 页面需要做页面统计,需要访问域. 访问域方法: using System.DirectoryServices.AccountManagement;命名空间负责管理. MSDN:https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement%28v=vs.110%29.aspx 这个类库相对比较复杂,还需要对AD有一定了解. 关键代码: private static string s

怎样从finally代码块里访问一个方法的结果值

虽然JVM是一种基于栈的引擎,但Java语言没有真正提供访问栈的方式.即使在某些很少的情况下,这样做很有用. 一个例子 方法的result值放在了栈里面.如果你看下面的例子: public int method() { if (something) return 1; ... if (somethingElse) return 2; ... return 0; } 如果我们忽略中止异常,错误处理和其他学术性的讨论.我们能说上面这个方法"肯定"会返回1,2或0.并且这个值在跳出方法之前就