Limiting the number of short-term accesses to a certain IP based on Nginx

Limiting the number of short-term accesses to a certain IP based on Nginx

How to set a limit on the number of visits to a certain IP in a certain period of time is a headache, especially when facing malicious DDOS attacks. Among them, CC attack (Challenge Collapsar) is a type of DDOS (Distributed Denial of Service) and also a common website attack method. The attacker continuously sends a large number of data packets to the victim host through a proxy server or zombie server, causing the other party's server resources to be exhausted until it crashes.

CC attacks usually use a limited number of IP addresses to frequently send data to the server to achieve the purpose of the attack. Nginx can prevent CC attacks by limiting the number of visits to an IP address in the same time period through the HttpLimitReqModule and HttpLimitZoneModule configurations.

HttpLimitReqModule is a module used to limit the number of connections per unit time. It uses the limit_req_zone and limit_req instructions together to achieve the limit. Once the number of concurrent connections exceeds the specified number, a 503 error is returned.

HttpLimitConnModule is used to limit the number of concurrent connections for a single IP address, using the limit_zone and limit_conn directives.

The difference between these two modules is that HttpLimitReqModule limits the number of connections within a period of time, while HttpLimitConnModule limits the number of connections at the same time.

HttpLimitReqModul limits the number of visits from the same IP address within a certain period of time

http{
  ...
  #Define a limit_req_zone named allips to store sessions, with a size of 10M memory.
  #Use $binary_remote_addr as the key and limit the average number of requests per second to 20.
  #1M can store 16000 states, the value of rete must be an integer,
  #If you limit one request per two seconds, you can set it to 30r/m
  limit_req_zone $binary_remote_addr zone=allips:10m rate=20r/s;
  ...
  server{
    ...
    location {
      ...

      #Limit each IP to no more than 20 requests per second, and the burst number of leaky buckets is 5
      #brust means that if the number of requests in the 1st, 2nd, 3rd, and 4th seconds is 19,
      #25 requests are allowed in the 5th second.
      #But if you make 25 requests in the first second, and more than 20 requests in the second second, a 503 error will be returned.
      #nodelay, if this option is not set, the average rate is strictly used to limit the number of requests.
      #When there are 25 requests in the first second, 5 requests will be executed in the second second.
      #Set nodelay, 25 requests will be executed in the 1st second.

      limit_req zone=allips burst=5 nodelay;
      ...
    }
    ...
  }
  ...
}

HttpLimitZoneModule limits the number of concurrent connections

limit_zone can only be defined in http scope, limit_conn can be defined in http server location scope

http{
  ...
  #Define a limit_zone named one with a memory size of 10M to store sessions.
  #Use $binary_remote_addr as key
  #After nginx 1.18, limit_conn is replaced by limit_conn_zone
  #and can only be placed in http scope limit_conn_zone one $binary_remote_addr 10m; 
  ...
  server{
    ...
    location {
      ...
      limit_conn one 20; #Connection limit#Bandwidth limit, limit the number of single connections. If one IP has two connections, it is 500x2k
      limit_rate 500k;      
      ...
    }
    ...
  }
  ...
}

nginx whitelist settings

The above configuration will restrict all IPs. Sometimes we don't want to restrict search engine spiders or our own test IPs.
For specific whitelist IPs, we can use the geo command to achieve it.

1.

http{
   geo$limited{
    default 1;
    #Google
    64.233.160.0/19 0;
    65.52.0.0/14 0;
    66.102.0.0/20 0;
    66.249.64.0/19 0;
    72.14.192.0/18 0;
    74.125.0.0/16 0;
    209.85.128.0/17 0;
    216.239.32.0/19 0;
    #M$
    64.4.0.0/18 0;
    157.60.0.0/16 0;
    157.54.0.0/15 0;
    157.56.0.0/14 0;
    207.46.0.0/16 0;
    207.68.192.0/20 0;
    207.68.128.0/18 0;
    #yahoo
    8.12.144.0/24 0;
    66.196.64.0/18 0;
    66.228.160.0/19 0;
    67.195.0.0/16 0;
    74.6.0.0/16 0;
    68.142.192.0/18 0;
    72.30.0.0/16 0;
    209.191.64.0/18 0;
    #My IPs
    127.0.0.1/32 0;
    123.456.0.0/28 0; #example for your server CIDR
  }

The geo directive defines a whitelist $limit variable with a default value of 1. If the client IP is within the above range, the value of $limit is 0.

2. Use the map command to map the search engine client's IP to an empty string. If it is not a search engine, the real IP will be displayed. In this way, the search engine IP cannot be stored in the limit_req_zone memory session, so the search engine IP access will not be restricted.

map $limited $limit {
1 $binary_remote_addr;
0 "";
}

3. Set limit_req_zone and limit_req

limit_req_zone $limit zone=foo:1m rate=10r/m;

limit_req zone=foo burst=5;

Finally, we use ab to compress php-fpm to test the effect of the above method.

Example 1: Limit the number of accesses to a configuration to 60 per minute, which is an average of 1 per second.

First we prepare a PHP script and put it in the root directory $document_root

test.php

<?
for( $i=0; $i < 1000; $i++)
echo 'Hello World';
?>

Nginx configuration adds limit_req_zone and limit_req

http{
  ...
  limit_req_zone $binary_remote_addr zone=allips:10m rate=60r/m;
  ...
  server{
    ...
    location {
      ...
      limit_req zone=allips;
      ...
    }
    ...
  }
  ...
}
# ab -n 5 -c 1 http://blog.rekfan.com/test.php
127.0.0.1- - [22/Dec/2012:06:27:06 +0000] "GET /test.php HTTP/1.0" 200 11000 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:06:27:06 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:06:27:07 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:06:27:07 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:06:27:07 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"

Without setting brust and nodelay, you can see that this configuration only allows one access per second, and requests exceeding this limit will return a 503 error.

http{
  ...
  limit_req_zone $binary_remote_addr zone=allips:10m rate=60r/m;
  ...
  server{
    ...
    location {
      ...
      limit_req zone=allips burst=1 nodelay;
      ...
    }
    ...
  }
  ...
}

# ab -n 5 -c 1 http://blog.rekfan.com/test.php
127.0.0.1- - [22/Dec/2012:07:01:00 +0000] "GET /test.php HTTP/1.0" 200 11000 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:07:01:00 +0000] "GET /test.php HTTP/1.0" 200 11000 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:07:01:01 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:07:01:01 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"
127.0.0.1 - - [22/Dec/2012:07:01:01 +0000] "GET /test.php HTTP/1.0" 503 537 "-" "Rekfan_Server/1.2.6"

Setting brust=1 and nodelay allows two requests to be processed in the first second.

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • nginx basic tutorial
  • Nginx Configuration Getting Started Tutorial
  • Getting Started Tutorial on nginx HTTP Server under Windows
  • What is Nginx load balancing and how to configure it
  • How to implement web page compression in Nginx optimization service
  • Six methods for nginx optimization
  • Detailed explanation of how Nginx solves the problem of cross-domain access to front-end resources
  • Solve the problem of Nginx returning 404 after configuring proxy_pass
  • Nginx configuration and compatibility with HTTP implementation code analysis
  • Nginx Service Quick Start Tutorial

<<:  MYSQL slow query and log settings and testing

>>:  Front-end state management (Part 1)

Recommend

Why web page encoding uses utf-8 instead of gbk or gb2312?

If you have a choice, you should use UTF-8 In fac...

Linux uses lsof command to check file opening status

Preface We all know that in Linux, "everythi...

nginx proxy_cache batch cache clearing script introduction

Preface: I used the official nginx proxy_cache as...

MySQL full backup and quick recovery methods

A simple MySQL full backup script that backs up t...

Introduction to the use of select optgroup tag in html

Occasionally, I need to group select contents. In ...

A detailed introduction to seata docker high availability deployment

Version 1.4.2 Official Documentation dockerhub st...

Nginx configuration based on multiple domain names, ports, IP virtual hosts

1. Type introduction 1.1 Domain-based virtual hos...

MySQL index leftmost principle example code

Preface I was recently reading about MySQL indexe...

18 sets of exquisite Apple-style free icon materials to share

Apple Mug Icons and Extras HD StorageBox – add on...

An article to help you understand jQuery animation

Table of contents 1. Control the display and hidi...

The current better way to make select list all options when selected/focused

During development, I encountered such a requireme...

A brief discussion on the execution details of Mysql multi-table join query

First, build the case demonstration table for thi...