简述
nginx 一般作为入口节点,除了承担业务方面的功能和性能要求外;
还有一定的安全配置需求;
隐藏内部信息
隐藏版本
server_tokens off;
如果是隐藏 server 名字, 需要修改源码重新编译, 不太推荐, 除非后续不咋更新, 否则很容易下次更新版本的时候遗漏了。
拒绝外部恶意请求
最基础的防盗链
referers 为空或者不为指定的域名之一,就给拒绝掉
1
2
3
4
5
6
|
location /images/ {
valid_referers none blocked www.ops.cn ops.cn;
if ($invalid_referer) {
return 404;
}
}
|
根据上一页面来源进行地址屏蔽
如果调用这个接口的页面不是指定页面就给拒绝掉
1
2
3
4
5
6
|
location ~ /account(/.*) {
if ($http_referer !~* "https://www.xxxxxxxx.net/account/xxxx") {
return 403;
}
proxy_pass http://web_group/account/;
}
|
限制请求方法
1
2
3
4
5
6
7
8
9
10
11
|
方法一
server {
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
}
方法二
location / {
limit_except GET HEAD POST { deny all; }
}
|
屏蔽源ip
能获取到真实源 ip 的场景
1
2
3
4
|
location / {
deny 192.168.1.1; # 单个ip
deny 192.168.1.0/24; # 屏蔽网段
}
|
白名单的方式
1
2
3
4
|
location / {
deny all;
allow 192.168.1.0/24; # 屏蔽网段
}
|
不能直接获取 ip, 需要 xff 头来获取ip的场景
一般取 xff 头的第一个ip地址作为在真实ip,
但是需要注意的是如果源端使用了正向代理出网, 这个 xff 第一个ip地址可能是假的, 所以最好是再加逻辑过滤出第一个公网ip来。
1
2
3
4
5
6
7
8
9
|
map $http_x_forwarded_for $clientRealIp {
"" $remote_addr;
~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
}
if ($clientRealIp ~* "111.111.111.111|111.111.111.112") {
return 403;
break;
}
|
简单做法
1
2
3
4
|
if ($http_x_forwarded_for ~* "1.1.1.1") {
return 403;
break;
}
|
url白名单
主要是过滤一些url扫描
非这些路径开头的请求都给拒绝掉
1
2
3
4
|
if ($request_uri !~ "^/abc/|^/api/|^/favicon.ico|^/html/|^/ops/|^/$|^/\?|^/images/") {
return 405;
break;
}
|
安全限流
限流主要有3个模块
- ngx_http_core_module 模块
limit_rate 这个指令可以用于控制速度,
limit_rate_after 用于设置http请求传输多少字节后开始限速,即不限速的初始量;
这2个命令都是限制的每一个连接的速度
- ngx_http_limit_conn_module 模块,用于连接数限制
- ngx_http_limit_req_module 模块,用于连接频率限制,主要是限制单个 IP 每秒请求数
实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
http {
limit_conn_zone $binary_remote_addr zone=limit1:10m;
imit_conn_zone $server_name zone=limit2:10m;
# 限制为每秒 2 次
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s;
server {
listen 80;
server_name example.com;
root /apps/project/webapp;
index index.html;
location / {
# 同一IP同一时间只允许10个连接
limit_conn limit1 10;
# 限制单一虚拟服务器的总连接数为2000
limit_conn limit2 2000;
}
location ^~ /interface {
# 漏桶数为 5,这个桶使用后, 是每秒补充一个的
# 场景1: 第1秒请求7个, 是可以的, 因为还有 5 个桶;
如果不设置 nodelay, 则多出的5 个请求会被延到第2秒去执行, 然后 3 个被延迟到第2秒去执行
设置 nodelay 后, 则都可以在第一秒执行
# 场景2: 第1-2-3-4 秒只请求2个, 则第5秒还是可以请求 7 个
limit_req zone=one burst=5 nodelay;
proxy_pass http://127.0.0.1:8080;
}
# 当请求流量总大小超过 500k 之后限速为 50k/s
location ^~ /flv/ {
limit_rate_after 500k; # 如果不设置软限制, 则直接使用 limit_rate
limit_rate 50k; # 限制单个连接的连接速率
}
access_log /data/log/nginx/nginx_access.log main;
}
}
|
关于给恶意用户的响应码
如果按照标准的 http resp code 来给响应, 好处是方便排错;
缺点就是恶意用户很快也能知道原因,然后用其它办法绕开
根据自身情况的考量,一般有这几种可以推荐
200 返回一个自定义的页面,或者直接响应首页的页面
403 显式拒绝
404 请求的资源不存在
444 直接关闭链接,不给任何响应