Nginx 基于 header 限制请求

说明

  • Nginx 自带 allow/deny 参数根据 IP 限制请求是否允许放行,如:
1
2
3
4
5
6
7
location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}
  • 但此配置的限制仅这对客户端的 IP,当 nginx 前还有其他服务,如 CDN、SLB 等设备时,此方法做限制存在问题,因为对 Nginx 来说更前侧的客户端 IP 是 F5 或 SLB 是 IP。
  • 但 CDN 或 SLB 在向后端转发请求时,一般会将用户的真实 IP 写入一个新 header 中,如 clientip,假设以 clientip 为例,配置 nginx 基于 header 头对网段或 ip 做限制。

配置

基于 IP 做限制

  • http 层增加 map,根据 clientip 赋值给 allow_access 不通的变量
    • 仅 clientip 为 192.168.212.11 或 192.168.212.12 时,赋值给 allow_access 为 allow
    • PS:非常规的 header 头使用时,变量前要加 http,如使用 clientip 时,变量名为 $http_clientip
1
2
3
4
5
6
7
8
9
http {
    map $http_clientip $allow_access{

        default "";
        "192.168.212.11" "allow";
        "192.168.212.12" "allow";

    }
}
  • server 层在要做限制的转发规则内配置限制
1
2
3
4
5
6
7
8
server{
    location ~* ^/aaa {
        if ($allow_access != "allow"){
                return 403;
        }
        return 200  "aaa ok";
    }
}
  • 进行测试,仅被匹配复制为 allow 的请求可正常请求
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 11、12 正常放行
$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.212.11"
HTTP/1.1 200 OK

$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.212.12"
HTTP/1.1 200 OK

# 15、50 被拦截
$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.212.15"
HTTP/1.1 403 Forbidden

$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.212.50"
HTTP/1.1 403 Forbidden

基于网段匹配

  • 仅更改 http 层,http 层内使用正则将 ip 当作字符串进行匹配,如 192.168.212.0/24 实际匹配 192.168.212. 开头的 IP
1
2
3
4
5
6
7
8
http {
    map $http_clientip $allow_access{

        default "";
        ~^192\.168\.212\.\d+$ "allow";

    }
}
  • 测试
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 192.168.212. 开头的正常放行
$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.212.10"
HTTP/1.1 200 OK

$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.212.50"
HTTP/1.1 200 OK

# 非 192.168.212. 开头的被拦截
$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.211.50"
HTTP/1.1 403 Forbidden

$ curl "http://127.0.0.1:8000/aaa" -I -X GET -H "clientip: 192.168.100.10"
HTTP/1.1 403 Forbidden