Realization of limiting short time access times of an IP based on Nginx

  • 2021-10-11 19:58:17
  • OfStack

How to limit the number of times a certain IP can be accessed in a certain time period is a headache, especially in the face of malicious ddos attacks. Among them, CC attack (Challenge Collapsar) is a kind of DDOS (Distributed Denial of Service), and it is also a common website attack method. The attacker constantly sends a large number of data packets to the victim host through proxy server or broiler, causing the server resources of the other party to be exhausted until it goes down and crashes.

cc attack 1 generally uses a limited number of ip to send data frequently to the server to achieve the purpose of attack. nginx can limit the access times of ip in the same time period through HttpLimitReqModul and HttpLimitZoneModule configuration to prevent cc attack.

HttpLimitReqModul is used to limit the number of connections per unit time. The limit_req_zone and limit_req instructions are used together to achieve the limit. 1 If the number of concurrent connections exceeds the specified number, a 503 error will be returned.

HttpLimitConnModul is used to limit the number of concurrent connections for a single ip using the limit_zone and limit_conn directives

The difference between these two modules is that HttpLimitReqModul is a limit on the number of connections within a period of time, and HttpLimitConnModul is a limit on the number of connections at the same time

HttpLimitReqModul restricts the number of access instances of the same ip in a certain period of time


http{
  ...
  # Definition 1 A person named allips Adj. limit_req_zone Used to store session The size is 10M Memory, 
  # With $binary_remote_addr  For key, Limit the average request per second to 20 A, 
  #1M Energy storage 16000 A state, rete The value of must be an integer, 
  # If you limit it to two seconds 1 Request, which can be set to 30r/m
  limit_req_zone $binary_remote_addr zone=allips:10m rate=20r/s;
  ...
  server{
    ...
    location {
      ...

      # Limit every ip Not exceeding per second 20 Number of requests, number of leaky buckets burst For 5
      #brust It means that if the first 1 Seconds, 2,3,4 Second request is 19 A, 
      # No. 1 5 The request for seconds is 25 One is allowed. 
      # But if you don't 1 In seconds 25 A request, the first 2 Seconds over 20 Returns the request of 503 Error. 
      #nodelay If this option is not set, strictly use the average rate to limit the number of requests, 
      # No. 1 1 Seconds 25 At the request, 5 The first request is placed in the first 2 Second execution, 
      # Settings nodelay , 25 The request will be in the first 1 Execute in seconds. 

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

HttpLimitZoneModule Limit Concurrent Connections Instance

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


http{
  ...
  # Definition 1 A person named one Adj. limit_zone, Size 10M Memory to store session , 
  # With $binary_remote_addr  For key
  #nginx 1.18 Use later limit_conn_zone Replaced limit_conn
  # And can only be placed in http Scope 
  limit_conn_zone  one $binary_remote_addr 10m; 
  ...
  server{
    ...
    location {
      ...
      limit_conn one 20;     # Connections limit 
      # Bandwidth limitation , For a single connection limit, if 1 A ip Two connections, that is 500x2k
      limit_rate 500k;      
      ...
    }
    ...
  }
  ...
}

nginx White List Settings

The above configuration will restrict all ip. Sometimes we don't want to restrict the spider of search engine or test ip ourselves.
For a specific whitelist ip, we can implement it with the help of geo instruction.

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 $limited variable, with a default value of 1. If the client ip is in the above range, the value of $limited is 0

2. Use the map instruction to map the ip of the search engine client to be an empty string. If it is not a search engine, the real ip will be displayed, so that the search engine ip cannot be stored in the memory session of limit_req_zone, so the ip access of the search engine 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 press php-fpm to actually test the effect of the above method

Example 1: Limit only allows one ip to access the configuration 60 times in 1 minute, that is, an average of 1 time per second

First, we prepare an 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"

If brust and nodelay are not set, you can see that this configuration only allows access once per second, and the exceeded request returns 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.


Related articles: