【学习笔记】Nginx常用安全配置

一、Nginx的配置文件

在Linux系统中,Nginx配置文件在 /usr/local/nginx/conf/ 目录中

先看一下nginx.conf 文件结构:

bash 复制代码
	#user  nobody;
	worker_processes  1;

	#error_log  logs/error.log;
	#error_log  logs/error.log  notice;
	#error_log  logs/error.log  info;

	#pid        logs/nginx.pid;

	events {
	    worker_connections  1024;
	}

	http {
	    include       mime.types;
	    default_type  application/octet-stream;

	    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
	    #                  '$status $body_bytes_sent "$http_referer" '
	    #                  '"$http_user_agent" "$http_x_forwarded_for"';

	    #access_log  logs/access.log  main;

	    sendfile        on;
	    #tcp_nopush     on;

	    #keepalive_timeout  0;
	    keepalive_timeout  65;

	    #gzip  on;

	    server {
	        listen       80;
	        server_name  localhost;

	        #charset koi8-r;

	        #access_log  logs/host.access.log  main;

	        location / {
	            root   html;
	            index  index.html index.htm;
	        }

	        #error_page  404              /404.html;

	        # redirect server error pages to the static page /50x.html
	        #
	        error_page   500 502 503 504  /50x.html;
	        location = /50x.html {
	            root   html;
	        }
	    }
	}

(1)全局块

从配置文件开始到 events 块之间的内容,主要会设置一些影响 nginx 服务器整体运行的配置指令,主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。

比如上面第一行的配置:

bash 复制代码
worker_processes 1;

这是 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的制约。

(2)events 块

比如上面的配置:

bash 复制代码
events { worker_connections 1024; }

events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。上述例子就表示每个 work process 支持的最大连接数为 1024。

这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。

(3)http块

这算是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。
需要注意的是:http 块包括 http 全局块 和 server 块。

①http 全局块

http 全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。

②server 块

这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本。

每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。

而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。

1)全局 server 块

最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或 IP 配置。

2)location 块

一个 server 块可以配置多个 location 块。这块的主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称(也可以是 IP 别名)之外的字符串(例如前面的 /uri-string)进行匹配,对特定的请求进行处理。

地址定向、数据缓存和应答控制等功能,还有许多第三方模块的配置也在这里进行。

bash 复制代码
#定义Nginx运行的用户和用户组
user www www;
#
#nginx进程数,建议设置为等于CPU总核心数.
worker_processes 8;
#
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;
#
#进程文件
pid /var/run/nginx.pid;
#
#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致.
worker_rlimit_nofile 65535;
#
#工作模式与连接数上限
events
{
    #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型.
    use epoll;
    #单个进程最大连接数(最大连接数=连接数*进程数)
    worker_connections 1024;    #最大连接数,默认为512
}
#
#设定http服务器
http
{
    include mime.types; #文件扩展名与文件类型映射表
    default_type application/octet-stream; #默认文件类型
    #charset utf-8; #默认编码
    server_names_hash_bucket_size 128; #服务器名字的hash表大小
    client_header_buffer_size 32k; #上传文件大小限制
    large_client_header_buffers 4 64k; #设定请求缓
    client_max_body_size 8m; #设定请求缓
      keepalive_timeout 65;  #连接超时时间,默认为75s,可以在http,server,location块。
    # 开启目录列表访问,合适下载服务器,默认关闭.
    autoindex on; # 显示目录
    autoindex_exact_size on; # 显示文件大小 默认为on,显示出文件的确切大小,单位是bytes 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB
    autoindex_localtime on; # 显示文件时间 默认为off,显示的文件时间为GMT时间 改为on后,显示的文件时间为文件的服务器时间
    
    sendfile on; # 开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载.注意:如果图片显示不正常把这个改成off.
    tcp_nopush on; # 防止网络阻塞
    tcp_nodelay on; # 防止网络阻塞
    
    
    # FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度.下面参数看字面意思都能理解.
    fastcgi_connect_timeout 300; ## 链接
    fastcgi_send_timeout 300;  ##读取 是指nginx进程向fastcgi进程发送request的整个过程的超时时间
    fastcgi_read_timeout 300;  ##发请求 是指fastcgi进程向nginx进程发送response的整个过程的超时时间
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;
    
    # gzip模块设置
    gzip on; #开启gzip压缩输出
    gzip_min_length 1k; #允许压缩的页面的最小字节数,页面字节数从header偷得content-length中获取.默认是0,不管页面多大都进行压缩.建议设置成大于1k的字节数,小于1k可能会越压越大
    gzip_buffers 4 16k; #表示申请4个单位为16k的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果
    gzip_http_version 1.1; #压缩版本(默认1.1,目前大部分浏览器已经支持gzip解压.前端如果是squid2.5请使用1.0)
    gzip_comp_level 2; #压缩等级.1压缩比最小,处理速度快.9压缩比最大,比较消耗cpu资源,处理速度最慢,但是因为压缩比最大,所以包最小,传输速度快
    gzip_types text/plain application/x-javascript text/css application/xml;
    #压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn.
    gzip_vary on;#选项可以让前端的缓存服务器缓存经过gzip压缩的页面.例如:用squid缓存经过nginx压缩的数据
    
    #开启限制IP连接数的时候需要使用
    #limit_zone crawler $binary_remote_addr 10m;
    
    ##upstream的负载均衡,四种调度算法(下例主讲)##
    
    #虚拟主机的配置
    server
    {
        # 监听端口
        listen 80;
        # 域名可以有多个,用空格隔开
        server_name 127.0.0.1;
        # HTTP 自动跳转 HTTPS
        rewrite ^(.*) https://www.baidu.com;
        deny 127.0.0.1;  #拒绝的ip
        allow 172.18.5.54; #允许的ip 
    }
    upstream myserver {   
      server 127.0.0.1:8080;
      server 192.168.24.189:8080 backup;  #热备
    }
    server
    {
        # 监听端口 HTTPS
        listen 443 ssl;
        server_name https://www.baidu.com;
        root /data/www/;
        # 配置域名证书
        ssl_certificate      C:\WebServer\Certs\certificate.crt;
        ssl_certificate_key  C:\WebServer\Certs\private.key;
        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
        ssl_protocols SSLv2 SSLv3 TLSv1;
        ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
        ssl_prefer_server_ciphers  on;
    
        index index.html index.htm index.php;
        
        location ~ .*\.(php|php5)?$
        {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi.conf;
        }
        
        # 配置地址拦截转发,解决跨域验证问题
        location /oauth/{
            proxy_pass https://localhost:13580/oauth/;
            proxy_set_header HOST $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        
        # 图片缓存时间设置
        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
            expires 10d;
        }
        
        # JS和CSS缓存时间设置
        location ~ .*\.(js|css)?$ {
            expires 1h;
        }

        # 日志格式设定
        log_format access '$server_name $remote_addr -$remote_user [$time_local] "$request"'
                  '$status $uptream_status $body_bytes_sent "$http_referer"'
                  '"$http_user_agent" "$http_x_forwarded_for" '
                  '$ssl_protocol $ssl_cipher $upstream_addr $request_time $upstream_response_time';
       # 定义本虚拟主机的访问日志
        access_log /var/log/nginx/access.log access;
        
        # 设定查看Nginx状态的地址.StubStatus模块能够获取Nginx自上次启动以来的工作状态,此模块非核心模块,需要在Nginx编译安装时手工指定才能使用
        location /NginxStatus {
            stub_status on;
            access_log on;
            auth_basic "NginxStatus";
            auth_basic_user_file conf/htpasswd;
            #htpasswd文件的内容可以用apache提供的htpasswd工具来产生.
        }
    }
}

二、Nginx的安全配置

2.1 隐藏版本号

bash 复制代码
http {
    # 关闭在响应头中显示Nginx版本号
    # 默认响应头: Server: nginx/1.18.0
    # 关闭后响应头: Server: nginx
    server_tokens off;
}

经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞。

2.2 开启HTTPS

默认情况下,nginx监听在80端口(HTTP)和443端口(HTTPS)。

复制代码
server {
    listen 443;
    server_name ops-coffee.cn;

    ssl on;
    ssl_certificate /etc/nginx/server.crt;
    ssl_certificate_key /etc/nginx/server.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
}

可以使用openssl命令生成SSL证书:

bash 复制代码
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx.key -out nginx.crt
bash 复制代码
ssl_certificate /path/to/nginx.crt;
ssl_certificate_key /path/to/nginx.key;

或者

bash 复制代码
server {
    # 监听443端口,启用SSL
    listen 443 ssl;
    
    # 指定SSL证书路径
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    # 将所有HTTP请求重定向到HTTPS
    if ($scheme != "https") {
        return 301 https://$server_name$request_uri;
    }
    
    # 启用HSTS,强制浏览器在指定时间内使用HTTPS访问
    add_header Strict-Transport-Security "max-age=31536000" always;
}

ssl on: 开启https

ssl_certificate: 配置nginx ssl证书的路径

ssl_certificate_key: 配置nginx ssl证书key的路径

bash 复制代码
使用更安全的SSL配置参数:

# 只允许TLS 1.2和1.3版本,禁用不安全的SSL和早期TLS版本
ssl_protocols TLSv1.2 TLSv1.3;

# 配置加密套件,按推荐顺序排列
# ECDHE: 使用椭圆曲线密钥交换
# AES-GCM: 使用AES-GCM加密模式
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

# 优先使用服务器的加密套件
ssl_prefer_server_ciphers on;

# 配置SSL会话缓存,提高性能
# shared:SSL:10m: 所有工作进程共享的缓存,大小为10MB
ssl_session_cache shared:SSL:10m;

# SSL会话超时时间
ssl_session_timeout 10m;

# 启用OCSP Stapling,提供证书状态信息
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

ssl_protocols: 指定客户端建立连接时使用的ssl协议版本,如果不需要兼容TSLv1,直接去掉即可

ssl_ciphers: 指定客户端连接时所使用的加密算法,你可以在这里配置更高安全的算法

2.3 添加黑白名单

白名单配置

bash 复制代码
location /admin/ {
    # 允许内网IP段访问
    # 192.168.1.0/24: 允许192.168.1.x网段的所有IP
    allow 192.168.1.0/24;
    
    # 允许另一个内网IP段访问
    allow 10.0.0.0/8;
    
    # 拒绝其他所有IP访问
    deny all;
    
    # 开启基础认证
    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

上边表示只允许192.168.1.0/24网段的主机访问,拒绝其他所有

也可以写成黑名单的方式禁止某些地址访问,允许其他所有,例如

复制代码
location /ops-coffee/ {
    deny   192.168.1.0/24;
    allow    all;
}

更多的时候客户端请求会经过层层代理,我们需要通过$http_x_forwarded_for来进行限制,可以这样写

复制代码
set $allow false;
if ($http_x_forwarded_for = "211.144.204.2") { set $allow true; }
if ($http_x_forwarded_for ~ "108.2.66.[89]") { set $allow true; }
if ($allow = false) { return 404; }

2.4 添加账号认证

复制代码
server {
    location / {
        auth_basic "please input user&passwd";
        auth_basic_user_file key/auth.key;
    }
}

关于账号认证《Nginx的几个常用配置和技巧》文章中已有详细介绍,这里不赘述

2.5 限制请求方法

复制代码
if ($request_method !~ ^(GET|POST)$ ) {
    return 405;
}

$request_method能够获取到请求nginx的method

配置只允许GET\POST方法访问,其他的method返回405

2.6 拒绝User-Agent

复制代码
if ($http_user_agent ~* LWP::Simple|BBBike|wget|curl) {
    return 444;
}

可能有一些不法者会利用wget/curl等工具扫描我们的网站,我们可以通过禁止相应的user-agent来简单的防范。Nginx的444状态比较特殊,如果返回444那么客户端将不会收到服务端返回的信息,就像是网站无法连接一样

2.7 图片防盗链

复制代码
location /images/ {
    valid_referers none blocked www.ops-coffee.cn ops-coffee.cn;
    if ($invalid_referer) {
        return  403;
    }
}

valid_referers: 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为www.ops-coffee.cn或ops-coffee.cn时访问images下的图片资源,否则返回403

当然你也可以给不符合referer规则的请求重定向到一个默认的图片,比如下边这样

复制代码
location /images/ {
    valid_referers blocked www.ops-coffee.cn ops-coffee.cn
    if ($invalid_referer) {
        rewrite ^/images/.*\.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;
    }
}

2.8 控制并发连接数

可以通过ngx_http_limit_conn_module模块限制一个IP的并发连接数

bash 复制代码
http {
    # 定义一个共享内存区域,用于存储IP连接数信息
    # $binary_remote_addr: 使用二进制格式存储客户端IP,节省空间
    # zone=addr:10m: 指定共享内存区域名称为addr,大小为10MB
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    
    # 限制每个IP同时最多100个连接
    limit_conn addr 100;
    
    # 定义请求频率限制,每个IP每秒最多10个请求
    # rate=10r/s: 每秒10个请求
    limit_req_zone $binary_remote_addr zone=req_zone:10m rate=10r/s;
    
    # 应用请求频率限制,burst=20表示最多允许20个请求排队
    limit_req zone=req_zone burst=20 nodelay;
}

limit_conn_zone: 设定保存各个键(例如$binary_remote_addr)状态的共享内存空间的参数,zone=空间名字:大小

大小的计算与变量有关,例如$binary_remote_addr变量的大小对于记录IPV4地址是固定的4 bytes,而记录IPV6地址时固定的16 bytes,存储状态在32位平台中占用32或者64 bytes,在64位平台中占用64 bytes。1m的共享内存空间可以保存大约3.2万个32位的状态,1.6万个64位的状态

limit_conn: 指定一块已经设定的共享内存空间(例如name为ops的空间),以及每个给定键值的最大连接数

上边的例子表示同一IP同一时间只允许10个连接

当有多个limit_conn指令被配置时,所有的连接数限制都会生效

复制代码
http {
    limit_conn_zone $binary_remote_addr zone=ops:10m;
    limit_conn_zone $server_name zone=coffee:10m;

    server {
        listen       80;
        server_name  ops-coffee.cn;

        root /home/project/webapp;
        index index.html;

        location / {
            limit_conn ops 10;
            limit_conn coffee 2000;
        }
    }
}

上边的配置不仅会限制单一IP来源的连接数为10,同时也会限制单一虚拟服务器的总连接数为2000。

2.9 缓冲区溢出攻击

缓冲区溢出攻击 是通过将数据写入缓冲区并超出缓冲区边界和重写内存片段来实现的,限制缓冲区大小可有效防止

bash 复制代码
## Start: Size Limits & Buffer Overflows ##
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
## END: Size Limits & Buffer Overflows ##

client_body_buffer_size: 默认8k或16k,表示客户端请求body占用缓冲区大小。如果连接请求超过缓存区指定的值,那么这些请求实体的整体或部分将尝试写入一个临时文件。

client_header_buffer_size: 表示客户端请求头部的缓冲区大小。绝大多数情况下一个请求头不会大于1k,不过如果有来自于wap客户端的较大的cookie它可能会大于 1k,Nginx将分配给它一个更大的缓冲区,这个值可以在large_client_header_buffers里面设置

client_max_body_size: 表示客户端请求的最大可接受body大小,它出现在请求头部的Content-Length字段, 如果请求大于指定的值,客户端将收到一个"Request Entity Too Large" (413)错误,通常在上传文件到服务器时会受到限制

large_client_header_buffers 表示一些比较大的请求头使用的缓冲区数量和大小,默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,请求字段不能大于一个缓冲区大小,如果客户端发送一个比较大的头,nginx将返回"Request URI too large" (414),请求的头部最长字段不能大于一个缓冲区,否则服务器将返回"Bad request" (400)

同时需要修改几个超时时间的配置,防止慢速攻击

bash 复制代码
# 客户端请求体超时时间,单位秒
client_body_timeout 10;

# 客户端请求头超时时间
client_header_timeout 10;

# 客户端保持连接超时时间
# 第一个参数是客户端超时时间
# 第二个参数是在响应头中的Keep-Alive超时时间
keepalive_timeout 5 5;

# 向客户端发送响应的超时时间
send_timeout 10;

# 读取代理服务器响应的超时时间
proxy_read_timeout 10;

# 连接代理服务器的超时时间
proxy_connect_timeout 10;

client_body_timeout: 表示读取请求body的超时时间,如果连接超过这个时间而客户端没有任何响应,Nginx将返回"Request time out" (408)错误

client_header_timeout: 表示读取客户端请求头的超时时间,如果连接超过这个时间而客户端没有任何响应,Nginx将返回"Request time out" (408)错误

keepalive_timeout: 参数的第一个值表示客户端与服务器长连接的超时时间,超过这个时间,服务器将关闭连接,可选的第二个参数参数表示Response头中Keep-Alive: timeout=time的time值,这个值可以使一些浏览器知道什么时候关闭连接,以便服务器不用重复关闭,如果不指定这个参数,nginx不会在应Response头中发送Keep-Alive信息

send_timeout: 表示发送给客户端应答后的超时时间,Timeout是指没有进入完整established状态,只完成了两次握手,如果超过这个时间客户端没有任何响应,nginx将关闭连接

2.10 Header头设置

通过以下设置可有效防止XSS攻击

bash 复制代码
# 防止网站被嵌入恶意网页中,避免点击劫持
add_header X-Frame-Options "SAMEORIGIN";

# 启用浏览器XSS防护功能,并在检测到攻击时,停止渲染页面
add_header X-XSS-Protection "1; mode=block";

# 禁止浏览器猜测(嗅探)资源的MIME类型,防止资源类型混淆攻击
add_header X-Content-Type-Options "nosniff";

# 控制引用地址信息的传递,增强隐私保护
add_header Referrer-Policy "strict-origin-origin-when-cross-origin";

# 内容安全策略,控制资源加载来源,防止XSS等攻击
# default-src 'self': 只允许加载同源资源
# http: https:: 允许通过HTTP和HTTPS加载资源
# data:: 允许data:URI的资源(如base64编码的图片)
# blob:: 允许blob:URI的资源(如视频流)
# 'unsafe-inline': 允许内联脚本和样式(根据需要配置)
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'";

X-Frame-Options: 响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套

X-XSS-Protection: 表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面

X-Content-Type-Options: 响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为,nosniff 表示不允许任何猜测

在通常的请求响应中,浏览器会根据Content-Type来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用MIME-sniffing来猜测资源的响应类型,这是非常危险的

例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果

另外还有几个关于请求头的安全配置需要注意

Content-Security-Policy: 定义页面可以加载哪些资源,

复制代码
add_header Content-Security-Policy "default-src 'self'";

上边的配置会限制所有的外部资源,都只能从当前域名加载,其中default-src定义针对所有类型资源的默认加载策略,self允许来自相同来源的内容

Strict-Transport-Security: 会告诉浏览器用HTTPS协议代替HTTP来访问目标站点

复制代码
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

上边的配置表示当用户第一次访问后,会返回一个包含了Strict-Transport-Security响应头的字段,这个字段会告诉浏览器,在接下来的31536000秒内,当前网站的所有请求都使用https协议访问,参数includeSubDomains是可选的,表示所有子域名也将采用同样的规则

2.11 文件上传安全

  1. 限制上传文件大小

防止通过上传大文件耗尽服务器资源:

bash 复制代码
# 限制请求体大小,即上传文件的最大大小为10MB
client_max_body_size 10m;

# 设置请求体缓冲区大小为128KB
# 超过此大小的请求体会被写入临时文件
client_body_buffer_size 128k;

# 配置临时文件存储路径
client_body_temp_path /var/nginx/client_body_temp;
  1. 配置上传目录权限

确保上传目录的权限配置正确:

bash 复制代码
location /uploads/ {
    # 指定上传根目录
    root /var/www/uploads;
    
    # 指定临时文件目录
    client_body_temp_path /var/www/tmp;
    
    # 允许的WebDAV方法
    dav_methods PUT DELETE MKCOL COPY MOVE;
    
    # 自动创建上传目录
    create_full_put_path on;
    
    # 设置目录访问权限
    # user:rw - 文件所有者可读写
    # group:rw - 组用户可读写
    # all:r - 其他用户只读
    dav_access user:rw group:rw all:r;
    
    # 限制上传文件类型
    if ($request_filename ~* ^.*?\.(php|php5|sh|pl|py)$) {
        return 403;
    }

2.12 防止常见攻击

1)防止SQL注入

配置特殊字符过滤。

bash 复制代码
location / {
    # 检查URL中是否包含特殊字符
    # 如果包含分号、单引号、尖括号等字符,返回444状态码
    # 444是Nginx特殊状态码,表示关闭连接而不发送响应头
    if ($request_uri ~* [;'<>] ) {
        return 444;
    }
    
    # 检查查询字符串中的特殊字符
    if ($args ~* [;'<>] ) {
        return 444;
    }
    
    # 保护敏感URI
    location ~* /(admin|backup|config|db|src)/ {
        deny all;
    }
}

nginx可以通过使用正则表达式过滤请求来防御此类攻击。

bash 复制代码
location / {
    if ($args ~ "(?i)[\s'"]+(union|select|insert|update|delete)[\s'"]+) {
        return 403;
    }
}

2)防御跨站脚本攻击(XSS)

跨站脚本攻击(XSS)是通过将恶意脚本注入到Web应用程序中来攻击用户浏览器。nginx可以通过使用正则表达式过滤请求来防御此类攻击。

bash 复制代码
location / {
    if ($args ~ "(?i)<script(.*?)>(.*?)</script>") {
        return 403;
    }
}

3)防御文件包含攻击

文件包含攻击是通过将恶意文件包含到Web应用程序中来攻击服务器。nginx可以通过使用正则表达式过滤请求来防御此类攻击。

bash 复制代码
location / {
    if ($args ~ "(?i)[\s'"]+(include|require)[\s'"]+) {
        return 403;
    }
}

4)防止目录遍历

禁止访问隐藏文件和目录:

bash 复制代码
# 禁止访问所有以点开头的隐藏文件和目录
location ~ /\. {
    # 拒绝所有请求
    deny all;
    
    # 禁止记录访问日志
    access_log off;
    
    # 禁止记录404错误日志
    log_not_found off;
}

# 禁止访问特定目录
location ~* ^/(uploads|images)/.*\.(php|php5|sh|pl|py|asp|aspx|jsp)$ {
    deny all;
}

# 防止目录列表
location / {
    autoindex off;
}

2.13 日志安全

1)配置访问日志

详细记录访问信息,便于安全分析:

bash 复制代码
# 定义详细的日志格式
log_format detailed '$remote_addr - $remote_user [$time_local] '  # 记录客户端IP和访问时间
                    '"$request" $status $body_bytes_sent '        # 记录请求信息、状态码和发送字节数
                    '"$http_referer" "$http_user_agent" '        # 记录来源页面和用户代理
                    '$request_time $upstream_response_time';      # 记录请求处理时间和上游响应时间

# 配置访问日志
# buffer=32k: 使用32KB缓冲区
# flush=5s: 每5秒刷新一次日志
access_log /var/log/nginx/access.log detailed buffer=32k flush=5s;

# 对于静态资源,可以关闭访问日志以提高性能
location /static/ {
    access_log off;
}

访问日志记录了每个请求的详细信息,包括请求时间、请求方法、请求URL、请求头、响应状态代码和响应大小。这些日志对于故障排除、安全分析和性能优化至关重要。

2)配置错误日志

设置适当的错误日志级别:

bash 复制代码
# 设置错误日志级别为warn
# 可选级别: debug, info, notice, warn, error, crit, alert, emerg
error_log /var/log/nginx/error.log warn;

# 对于开发环境,可以使用debug级别获取更多信息
# error_log /var/log/nginx/error.log debug;

2.14 禁止执行脚本

在静态资源目录中禁止执行脚本:

bash 复制代码
location /static/ {
    # 禁止执行PHP文件
    location ~ \.(php|php5)$ {
        deny all;
    }
    
    # 只允许特定文件类型
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 30d;  # 设置缓存时间
        add_header Cache-Control "public, no-transform";
    }
}

三、Nginx部署及环境优化

1 删除所有不需要的Nginx模块

直接通过编译Nginx源代码使模块数量最少化。通过限制只允许Web服务器访问模块把风险降到最低。例如,禁用SSL和autoindex模块你可以执行以下命令:

复制代码
./configure --without-http_autoindex_module --without-http_ssi_module
make
make install

通过以下命令来查看当编译Nginx服务器时哪个模块能开户或关闭:

复制代码
./configure --help | less

然后禁用用不到的Nginx模块。

2 安装SELinux策略以强化Nginx Web服务器

默认的SELinux不会保护Nginx Web服务器,我这里安装和编译保护软件。
安装编译SELinux所需环境支持

复制代码
yum -y install selinux-policy-targeted selinux-policy-devel

下载SELinux策略以强化Nginx Web服务器。

复制代码
cd /opt
wget 'http://downloads.sourceforge.net/project/selinuxnginx/se-ngix_1_0_10.tar.gz?use_mirror=nchc'

解压、编译文件

复制代码
tar -zxvf se-ngix_1_0_10.tar.gz

编译文件

复制代码
cd se-ngix_1_0_10/nginx
make

将会输出如下:

复制代码
Compiling targeted nginx module
/usr/bin/checkmodule: loading policy configuration from tmp/nginx.tmp
/usr/bin/checkmodule: policy configuration loaded
/usr/bin/checkmodule: writing binary representation (version 6) to tmp/nginx.mod
Creating targeted nginx.pp policy package
rm tmp/nginx.mod.fc tmp/nginx.mod

安装生成的nginx.pp SELinux模块:

复制代码
/usr/sbin/semodule -i nginx.pp

3 在防火墙级限制每个IP的连接数

网络服务器必须监视连接和每秒连接限制。PF和Iptales都能够在进入你的Nginx服务器之前阻止最终用户的访问。

Linux Iptables:限制每次Nginx连接数

下面的例子会阻止来自一个IP的60秒钟内超过15个连接端口80的连接数。

复制代码
/sbin/iptables -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set
sbin/iptables -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 15 -j DROP
service iptables save

设置同一个IP 60秒内只允许10个Nginx链接。

4 配置操作系统保护Web服务器

Nginx程序一般以用户nginx运行。但是根目录(/nginx或者/usr /local/nginx/html)不应该设置属于用户nginx或对用户nginx可写。找出错误权限的文件可以使用如下命令:

复制代码
find /nginx -user nginx
find /usr/local/nginx/html -user nginx

确保你更所有权为root或其它用户,一个典型的权限设置

复制代码
/usr/local/nginx/html/
ls -l /usr/local/nginx/html/

示例输出:

复制代码
-rw-r--r-- 1 root root 925 Jan 3 00:50 error4xx.html
-rw-r--r-- 1 root root 52 Jan 3 10:00 error5xx.html
-rw-r--r-- 1 root root 134 Jan 3 00:52 index.html

删除由vim或其它文本编辑器创建的备份文件:

复制代码
find /nginx -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'
find /usr/local/nginx/html/ -name '.?*' -not -name .ht* -or -name '*~' -or -name '*.bak*' -or -name '*.old*'

通过find命令的-delete选项来删除这些文件,慎用,查找到就删除。

4 限制Nginx连接传出

黑客会使用工具如wget下载服务器本地的文件。使用Iptables从nginx用户来阻止传出连接。ipt_owner模块试图匹配本地产生的数据包的创建者。

下面的例子中只允许user用户在外面使用80连接。

复制代码
/sbin/iptables -A OUTPUT -o eth0 -m owner --uid-owner vivek \
-p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
相关推荐
今天背单词了吗9809 分钟前
算法学习笔记:19.牛顿迭代法——从原理到实战,涵盖 LeetCode 与考研 408 例题
笔记·学习·算法·牛顿迭代法
DKPT1 小时前
Java设计模式之行为型模式(观察者模式)介绍与说明
java·笔记·学习·观察者模式·设计模式
future14122 小时前
C#进阶学习日记
数据结构·学习
lxsy4 小时前
spring-ai-alibaba 1.0.0.2 学习(十六)——多模态
人工智能·学习·ai-alibaba
2301_797604244 小时前
学习记录:DAY36
学习
love-self-discipline5 小时前
带货视频评论洞察 Baseline 学习笔记 (Datawhale Al夏令营)
人工智能·笔记·学习
蜡笔小电芯6 小时前
【STM32】const 变量存储学习笔记
笔记·stm32·学习
恰薯条的屑海鸥6 小时前
前端进阶之路-从传统前端到VUE-JS(第五期-路由应用)
前端·javascript·vue.js·学习·前端框架
woodykissme7 小时前
齿轮主要的几项精度指标及检测项目学习
学习·机械·齿轮·齿轮精度