nginx安全配置

nginx安全配置

简述

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个模块

  1. ngx_http_core_module 模块
    limit_rate 这个指令可以用于控制速度,
    limit_rate_after 用于设置http请求传输多少字节后开始限速,即不限速的初始量;
    这2个命令都是限制的每一个连接的速度
  2. ngx_http_limit_conn_module 模块,用于连接数限制
  3. 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 直接关闭链接,不给任何响应