Nginx安全防护与HTTPS部署

目录

[一、Nginx 概述](#一、Nginx 概述)

[二、Nginx 核心安全配置](#二、Nginx 核心安全配置)

[(一)编译安装 Nginx](#(一)编译安装 Nginx)

(二)隐藏版本号

(三)限制危险请求方法

[(四)请求限制(CC 攻击防御)](#(四)请求限制(CC 攻击防御))

(五)防盗链

[三、Nginx 高级防护](#三、Nginx 高级防护)

(一)动态黑名单

[(二)Nginx HTTPS 配置](#(二)Nginx HTTPS 配置)


一、Nginx 概述

在互联网技术蓬勃发展的当下,Web 服务的安全性和可靠性至关重要。Nginx 作为一款高性能的 Web 服务器和反向代理工具,凭借其轻量级架构、卓越的高并发处理能力以及灵活的模块化设计,在全球 Web 服务器市场中占据近三分之一的份额,成为众多企业和开发者的首选。然而,网络攻击手段层出不穷,如 DDoS 攻击、SQL 注入、恶意爬虫等,同时数据隐私保护法规日益严格,如 GDPR、等保 2.0 等,这使得掌握 Nginx 的安全防护策略与 HTTPS 部署能力,成为运维工程师和开发者不可或缺的技能。

二、Nginx 核心安全配置

(一)编译安装 Nginx

  1. 安装支持软件:Nginx 的配置和运行依赖于 pcre、zlib 等软件包,因此需要预先安装这些软件的开发包(devel),以提供相应的库和头文件,确保 Nginx 安装顺利进行。在基于 DNF 包管理器的系统(如 OpenEuler)上,执行以下命令安装相关软件:

    [root@localhost ~]# dnf install -y gcc make pcre-devel zlib-devel openssl-devel perl-ExtUtils-MakeMaker git wget tar

  2. 创建运行用户、组和日志目录:为了提高安全性,创建专门的 Nginx 运行用户和组,并设置相应的日志目录。执行以下命令:

    [root@localhost ~]# useradd -M -s /sbin/nologin nginx
    [root@localhost ~]# mkdir -p /var/log/nginx
    [root@localhost ~]# chown -R nginx:nginx /var/log/nginx

  3. 编译安装 Nginx:下载 Nginx 源码包并解压,进入解压目录进行配置和编译安装。假设下载的 Nginx 版本为 1.26.3,执行以下命令:

    [root@localhost ~]# tar zxf nginx-1.26.3.tar.gz
    [root@localhost ~]# cd nginx-1.26.3
    [root@localhost nginx-1.26.3]#./configure
    --prefix=/usr/local/nginx
    --user=nginx
    --group=nginx
    --with-http_ssl_module
    --with-http_v2_module
    --with-http_realip_module
    --with-http_stub_status_module
    [root@localhost nginx-1.26.3]# make && make install

上述./configure命令中的参数含义如下:

  • --prefix=/usr/local/nginx:指定 Nginx 的安装路径。
  • --user=nginx--group=nginx:指定 Nginx 运行的用户和组。
  • --with-http_ssl_module:启用 HTTPS 支持。
  • --with-http_v2_module:启用 HTTP/2 支持。
  • --with-http_realip_module:用于获取客户端真实 IP 地址。
  • --with-http_stub_status_module:启用状态统计模块。

安装完成后,可以通过以下命令检查 Nginx 是否安装成功,并查看版本号:

复制代码
[root@localhost ~]# curl -I 192.168.10.101

如果 Nginx 正常运行,会返回类似如下信息,其中包含 Nginx 的版本号:

复制代码
HTTP/1.1 200 OK
Server: nginx/1.26.3
# 省略部分内容

(二)隐藏版本号

Nginx 的版本号可能会被攻击者利用,获取服务器的相关信息,增加安全风险。因此,需要隐藏 Nginx 的版本号。修改 Nginx 配置文件nginx.conf,在http块中添加server_tokens off;配置项:

复制代码
[root@localhost ~]# vi /usr/local/nginx/conf/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    # 隐藏版本号
    server_tokens off;
    # 省略部分内容
}

修改完成后,检查配置文件语法是否正确,并重新加载配置:

复制代码
[root@localhost ~]# nginx -t
[root@localhost ~]# nginx -s reload

再次使用curl -I命令检查,版本号已被隐藏:

复制代码
[root@localhost ~]# curl -I 192.168.10.101
HTTP/1.1 200 OK
Server: nginx
# 省略部分内容

(三)限制危险请求方法

TRACE、PUT、DELETE、CONNECT 等请求方法可能存在安全风险,如 TRACE 易引发 XST 攻击,PUT/DELETE 存在文件修改风险,CONNECT 可能导致代理滥用。通过正则表达式匹配请求方法,对非白名单方法返回 444(无响应关闭连接)。在 Nginx 配置文件nginx.confserver块中添加如下配置:

复制代码
[root@localhost ~]# vi /usr/local/nginx/conf/nginx.conf
server {
    if ($request_method!~ ^(GET|HEAD|POST)$) {
        return 444;
    }
    # 省略部分内容
}

修改完成后,同样检查配置文件语法并重新加载配置:

复制代码
[root@localhost ~]# nginx -t
[root@localhost ~]# nginx -s reload

验证测试请求,以 PUT 请求为例:

复制代码
[root@localhost ~]# curl -XPUT -I 192.168.10.101
curl: (52) Empty reply from server

查看access.log日志,可以看到相应的记录:

复制代码
192.168.10.101 - - [11/Mar/2025:18:30:46 +0800] "PUT / HTTP/1.1" 444 0 "-" "curl/8.4.0"

需要注意的是,测试 TRACE 和 CONNECT 方法时,状态码可能不是 444。原因如下:

  • CONNECT 请求的目标不是代理服务器时,服务器必须返回 400 Bad Request,Nginx 核心层在请求解析阶段直接拦截,根本不进入后续的 location 处理流程。
  • 现代 Nginx 默认禁用 TRACE 方法,在ngx_http_core_module阶段直接返回 405 Not Allowed。

(四)请求限制(CC 攻击防御)

CC 攻击(Challenge Collapsar 攻击)通过大量合法或伪造的小流量请求耗尽服务器资源,导致正常用户无法访问网站。可以使用 Nginx 的limit_req模块限制请求速率,使用limit_conn模块限制并发连接数。

  1. 使用 limit_req 模块限制请求速率 :编辑 Nginx 配置文件nginx.conf,在http块中定义限制区,在server块的location中实施速率限制:

    [root@localhost ~]# vi /usr/local/nginx/conf/nginx.conf
    http {
    # 定义限制区(10MB内存/每秒10请求)
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
    # 其他全局配置...
    server {
    location / {
    root html;
    index index.html index.php;
    limit_req zone=req_limit burst=20 nodelay;
    }
    }
    }

上述配置中关键参数说明如下:

  • limit_req_zone:定义共享内存区。
  • $binary_remote_addr:内置变量,表示客户端 IP 地址的二进制格式。
  • zone=req_limit:10m:创建名为req_limit的共享内存区,大小为 10M,用于存储客户端 IP。
  • rate=10r/s:限制并发数,每个 IP 每秒可以发起的请求次数为 10 次。
  • limit_req:实施速率限制。
  • zone=req_limit:绑定到预定义的共享内存区。
  • burst=20:类似等候区,超出并发数的请求会进入等候区,等候区占满后,多余的请求会立刻返回 503。
  • nodelay:立即处理突发请求而不延迟,相当于立即处理等候区的请求,多余的请求会立刻返回 503。
  1. 压力测试验证:安装 ApacheBench(简称 ab)测试工具,它是 Apache HTTP 服务器自带的轻量级、易用的 HTTP 服务器性能测试工具。执行以下命令安装:

    [root@localhost ~]# dnf install httpd-tools -y

发起测试请求,共发起 300 个请求,每次发起 30 个请求:

复制代码
[root@localhost ~]# ab -n 300 -c 30 http://192.168.10.101/

其中,-n 300表示总请求数为 300 次,即模拟客户端向服务器发送 300 次 HTTP 请求;-c30表示并发用户数为 30,即同时有 30 个请求并行发送到服务器。

查看access.log日志,会发现大量请求日志状态码为 503:

复制代码
[root@localhost ~]# tail -300 /usr/local/nginx/logs/access.log | grep -c 503
279

(五)防盗链

防盗链用于防止未经授权的用户盗用网站(静态)资源,保护网站的带宽和资源,避免版权侵犯。盗链行为是指一个网站在没有自身页面资源的情况下,链接到其他网站的资源展示给浏览者,增加自身访问量,同时损害原网站的合法利益,加重服务器负担。

  1. 准备工作 :本实验需要两台主机,分别为源主机(192.168.10.101,域名www.aaa.com)和盗链主机(192.168.10.102,域名www.bbb.com)。修改 Windows 的C:\Windows\System32\drivers\etc\hosts文件以及两台 OpenEuler 主机的hosts文件,设置域名和 IP 映射关系:

    192.168.10.101 www.aaa.com
    192.168.10.102 www.bbb.com

在源主机(www.aaa.com)的工作目录(假设为/usr/local/nginx/html)下放置图片kgc.png,并编辑原网站首页文件index.html

复制代码
[root@localhost ~]# vi /usr/local/nginx/html/index.html
<html>
<body>
<h1>aaa It work!</h1>
<img src="kgc.png"/>
</body>
</html>
  1. 测试盗链 :在盗链主机上安装httpd服务(用于模拟盗链网站),编辑盗链网站首页文件index.html

    [root@localhost ~]# dnf -y install httpd
    [root@localhost ~]# vi /usr/local/nginx/html/index.html

    <html> <body>

    bbb It work!

    </body> </html> [root@localhost ~]# systemctl stop firewalld [root@localhost ~]# systemctl start httpd

此时访问盗链网站(www.bbb.com),可以看到盗链成功,显示出源网站的图片。

  1. 配置 Nginx 防盗链 :在源主机的 Nginx 配置文件nginx.conf中添加防盗链配置:

    [root@localhost ~]# vi /usr/local/nginx/conf/nginx.conf
    location ^* .(gif|jpg|jpeg|png|bmp|swf|flv|mp4|webp|ico) { root html; valid_referers aaa.com *.aaa.com; if (invalid_referer) {
    return 403;
    }
    }

上述配置中:

  • ^*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|webp|ico)$:这段正则表达式表示匹配不区分大小写,以.jpg.gif.swf等结尾的文件。
  • valid_referers:设置信任的网站,可以正常使用图片。
  • if ($invalid_referer):如果链接的来源域名不在valid_referers所列出的列表中,$invalid_referer为 1,则执行后面的操作,即返回 403 页面。

修改完成后,检查配置文件语法并重新加载配置:

复制代码
[root@localhost ~]# nginx -t
[root@localhost ~]# nginx -s reload

再次访问盗链网站(www.bbb.com),会发现盗链失败,显示 403 页面。

三、Nginx 高级防护

(一)动态黑名单

动态黑名单是 Nginx 中一种实时拦截恶意请求的安全机制,允许在不重启服务的情况下,动态更新需要封禁的 IP 地址或网段,相比静态配置的allow/deny指令,更加灵活高效,适用于高并发、多变的攻击防护场景。

  1. 编辑黑名单配置文件 :创建或编辑黑名单配置文件blockips.conf,添加需要封禁的 IP 地址或网段,以及对应的封禁动作:

    [root@localhost ~]# vi /usr/local/nginx/conf/blockips.conf
    192.168.1.0/24 1; # 封禁整个网段
    192.168.10.102 1; # 封禁ip

IP 地址后的数字含义如下:

  • 0:允许访问。
  • 1:返回 403,完全封禁。
  • 2:返回 444,静默断开。
  • 3:返回 503,服务不可用。
  1. 编辑主配置文件 :在 Nginx 主配置文件nginx.conf中,使用geo模块引入黑名单配置,并设置相应的封禁逻辑:

    [root@localhost ~]# vi /usr/local/nginx/conf/nginx.conf
    http {
    geo block_ip { default 0; # 默认允许访问 include /usr/local/nginx/conf/blockips.conf; # 包含黑名单 } server { if (block_ip) {
    return 403; # 封禁动作
    }
    }
    }

上述配置中:

  • geo:Nginx 内置模块指令,专门用于处理 IP 地址相关的逻辑,基于客户端 IP 地址生成一个变量值,用于后续的访问控制判断。
  • $block_ip:自定义的变量名,存储计算结果(通常为 0 或 1)。
  • default 0:默认值,表示不在黑名单中的 IP 允许访问。
  • if ($block_ip):当变量值为 1 时触发封禁逻辑。

修改完成后,检查配置文件语法并重新加载配置:

复制代码
[root@localhost ~]# nginx -t
[root@localhost ~]# nginx -s reload
  1. 使用封禁 ip 测试访问 :使用封禁的 IP(如192.168.10.102)访问 Nginx 服务器,会返回 403 Forbidden 页面:

    [root@localhost ~]# curl 192.168.10.101

    <html> <head><title>403 Forbidden</title></head> <body>

    403 Forbidden


    nginx
    </body> </html>
  2. 自动添加黑名单:可以编写脚本实现自动封禁访问超过一定次数的 IP。例如,以下脚本可以自动封禁访问超过 100 次的 IP:

    #!/bin/bash

    自动封禁访问超过100次的IP

    awk '{print 1}' /var/log/nginx/access.log |sort |uniq -c|sort -nr | awk '{if(1>100) print $2" 1;"}' > /usr/local/nginx/conf/blockips.conf

上述脚本中:

  • awk '{print $1}' /var/log/nginx/access.log:从access.log日志文件中提取客户端 IP 地址。
  • sort:对提取的 IP 地址进行排序。
  • uniq -c:统计连续出现的次数,并在行首显示次数。
  • sort -nr:按数值从大到小排序。
  • awk '{if($1>100) print $2" 1;"}':筛选出访问次数大于 100 的 IP 地址,并添加封禁标记(返回 403)。
  • > /usr/local/nginx/conf/blockips.conf:将结果输出到黑名单配置文件中。

(二)Nginx HTTPS 配置

  1. HTTPS 概念

    • HTTPS 的设计初衷与发展:HTTPS(HyperText Transfer Protocol over Secure Socket Layer)的设计初衷是为了保证数据传输安全。国内大型互联网巨头从 2016 年开始大力推行 HTTPS,期间发生了一系列重大事件。例如,Google 搜索引擎让 HTTPS 的网站在搜索排名中更靠前;从 2017 年开始,chrome 浏览器把只采用 HTTP 的网站标记为不安全网站;苹果要求 App Store 中的所有应用都必须使用 HTTPS 加密链接;新一代的 http/2 协议的支持需要以 HTTPS 为基础。
    • HTTP 不安全的原因 :HTTP 由于是明文传输,主要存在三大风险:窃听风险、篡改风险、冒充风险。
      • 窃听风险:中间人可以获取到通信内容,由于内容是明文,所以获取明文后有安全风险。例如在转账场景中,中间人可以截获 "转账 100" 的信息,造成用户信息泄露和资金安全隐患 。
      • 篡改风险:中间人可以篡改报文内容后再发送给对方,风险极大。如将 "转账 100 到 A 账户" 篡改为 "转账 200 到其他账户" 。
      • 冒充风险:用户可能误以为在和合法网站通信,但实际上是在和钓鱼网站通信。比如以为是在和某宝通信,结果却是在和钓鱼网站交互。
    • 安全通信的四大原则 :安全的通信需要包括机密性、完整性、身份认证和不可否认这四个原则。
      • 机密性:对数据加密,解决了窃听风险。即使数据被中间人窃听,由于数据是加密的,也无法获取明文。
      • 完整性:数据在传输过程中没有被篡改,接收方能够识别数据是否被修改。一旦数据有任何改动,接收报文就会被判定为不合法。
      • 身份认证:确认对方的真实身份,解决了冒充风险。让用户不用担心访问的是正规网站却实际与钓鱼网站通信的问题。
      • 不可否认:不可否认已发生的行为。避免出现类似小明向小红借钱却不承认的情况,保障交易或行为的可追溯性和不可抵赖性。
    • HTTPS 通信原理简述
      • 对称加密的困境:HTTP 是明文传输,给报文加密可采用对称加密方式,即通信双方使用同一把密钥进行加解密。但问题在于,对称加密的密钥协商存在困难。如果通过报文直接传输密钥,密钥会被中间人截获和替换,导致后续通信依然不安全。例如,客户端向服务器请求密钥,中间人截获真密钥并返回假密钥,客户端使用假密钥加密报文,中间人就能用假密钥解密并篡改内容,再用真密钥加密篡改后的内容发送给服务器 。
      • 非对称加密的引入:非对称加密即加解密双方使用不同的密钥,一把作为公钥可以公开,一把作为私钥不能公开。公钥加密的密文只有私钥可以解密,私钥签名的内容只有公钥可以验签。服务器保管好私钥,发布公钥给客户端,客户端用公钥加密对称加密的密钥(或用于生成对称加密密钥的信息)传给服务器,服务器用私钥解密获得对称加密密钥,之后双方就可以用对称加密密钥进行通信。
      • 数字证书解决公钥传输信任问题:然而,服务器的公钥在传输过程中也存在被中间人调包的风险。为解决此问题,引入数字证书。服务器向证书颁发机构(CA)申请证书,在证书中附上公钥,客户端收到证书后,通过验证证书的合法性以及证书中的域名信息,来确认公钥的真实性。客户端拿到服务器端的公钥后,用公钥加密会话密钥(对称加密的密钥)发送给服务端,服务端用私钥解密获得会话密钥,然后双方就可以安全地进行数据传输。需要注意的是,HTTPS 加密采用混合模式,在握手阶段使用非对称加密,在数据传输阶段使用对称加密,因为对称加密的密钥管理简单且加密和解密效率更高。同时,中间人无法通过申请受信任的证书来替换服务器的证书,因为每个证书中的域名是唯一的,客户端会验证证书中的域名与实际访问的域名是否一致。
  2. Nginx 配置 HTTPS 证书

    • 使用 openssl 生成证书和私钥 :由于 SSL 证书需要向 CA 组织申购,在实验环境中可以采用自签名证书(自己给自己签名并颁发证书,这种证书不被信任,仅适用于测试场景)。
      • 创建证书存储目录:执行以下命令创建证书存储目录:

    [root@localhost ~]# mkdir -p /etc/nginx/ssl

  • 生成自签名证书:使用 openssl 命令生成自签名证书和私钥,执行以下命令:

    [root@localhost ~]# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx-selfsigned.key -out /etc/nginx/ssl/nginx-selfsigned.crt -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/CN=localhost"

  • 参数解释

    • -x509:生成自签名证书(而非 CSR)。
    • -nodes:不加密私钥(无密码保护)。
    • -days 365:证书有效期 1 年。
    • -keyout:指定私钥文件。
    • -out:指定自签名文件。
    • -newkey rsa:2048:生成 2048 位的 RSA 私钥。
    • -subj:设置证书主题信息(可按需修改字段)。
  • CA 签名证书与自签名证书对比

    • CA 签名证书:需要由受信任的第三方证书颁发机构(CA)签发。流程为用户生成私钥和 CSR(证书签名请求),将 CSR 提交给 CA(如 Let's Encrypt、DigiCert 等),CA 机构验证身份后,用 CA 的私钥对证书签名,生成最终证书。这种证书具有较高的信任度,适用于正式的线上环境。
    • 自签名证书:证书的颁发者(Issuer)和主体(Subject)是同一个实体(即自己)。无需第三方 CA 参与,直接用工具(如 OpenSSL)生成私钥和证书。签名时使用自己的私钥,而不是 CA 的私钥。适用于测试、内部环境或无需公开信任的场景。
  • Nginx 启用 HTTPS :编辑 Nginx 配置文件nginx.conf,添加 HTTPS 相关配置:

    [root@localhost ~]# vi /usr/local/nginx/conf/nginx.conf
    server {
    listen 443 ssl; # 监听HTTPS端口
    server_name localhost; # 域名或IP
    # 指定证书和私钥路径
    ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key;
    # SSL协议和加密套件配置(可选,提升安全性)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers on;
    # 其他配置(如根目录)
    location / {
    root /usr/local/nginx/html;
    index index.html;
    }
    # 可选:将HTTP请求重定向到HTTPS
    server {
    listen 80;
    server_name localhost;
    return 301 https://hostrequest_uri;
    }
    }

  • 配置说明

    • listen 443 ssl:表示 Nginx 监听 443 端口,并启用 SSL 加密。
    • server_name:指定服务器的域名或 IP 地址。
    • ssl_certificatessl_certificate_key:分别指定 SSL 证书和私钥的路径。
    • ssl_protocols:指定允许的 SSL/TLS 协议版本,这里启用了 TLSv1.2 和 TLSv1.3,TLSv1.0 和 TLSv1.1 因存在安全风险已被弃用。
    • ssl_ciphers:设置加密套件,选择安全强度较高的加密算法组合。
    • ssl_prefer_server_ciphers on:表示优先使用服务器端配置的加密套件。
    • location /:定义网站的根目录和默认首页。
    • 第二个server块配置用于将 HTTP 请求重定向到 HTTPS,确保所有访问都通过加密连接进行。
  • 检查配置并重启 Nginx:修改完成后,检查配置文件语法是否正确,并重新加载 Nginx 配置:

    [root@localhost ~]# nginx -t
    [root@localhost ~]# nginx -s reload

  • 通过浏览器验证 :访问https://你的服务器ip,由于使用的是自签名证书,浏览器会提示证书不安全。在测试环境中,可以选择 "高级"-"继续前往" 或 "信任此证书"(在正式环境中,应使用受信任的 CA 签名证书)。如果配置正确,将能够正常访问网站内容。

相关推荐
这是另一个世界4 分钟前
Kali Linux从入门到实战:系统详解与工具指南
linux·运维·服务器·网络·学习·web安全·网络安全
一丝晨光11 分钟前
Windows搭建Swift语言编译环境?如何构建ObjC语言编译环境?Swift如何引入ObjC框架?Interface Builder的历史?
linux·windows·macos·ios·objective-c·xcode·swift
静心问道27 分钟前
将 `/data` 盘中的所有数据迁移到 `/home/user/data` 目录下,然后将该磁盘与另一块磁盘组建 RAID 1
linux
qq_2906062741 分钟前
debian12.9或ubuntu,vagrant离线安装插件vagrant-libvirt
linux·ubuntu·vagrant
穷人小水滴2 小时前
在 Android 设备上写代码 (Termux, code-server)
android·linux·visual studio code
dessler3 小时前
Web服务器-Tomcat
linux·运维·tomcat
禾仔仔3 小时前
RISC-V特权模式及切换
linux·risc-v
好名字更能让你们记住我3 小时前
Linux多线程(六)之线程控制4【线程ID及进程地址空间布局】
linux·运维·服务器·开发语言·jvm·c++·centos
code monkey.4 小时前
【寻找Linux的奥秘】第九章:自定义SHELL
linux·shell·c/c++
繁华似锦respect4 小时前
SSL/TLS 协议详解:安全通信的基石
linux·服务器·c++·网络协议·安全·visualstudio·ssl