第5章:安全与性能

5.1 基础安全配置

5.1.1 隐藏Nginx版本信息

默认情况下,Nginx会在响应头中显示版本信息,这可能会泄露服务器的版本号,增加安全风险。

配置示例

http {
    # 隐藏Nginx版本信息
    server_tokens off;
    
    # ... 其他配置 ...
}

验证配置

curl -I http://localhost

预期输出(不包含版本号):

Server: nginx

而不是(包含版本号):

Server: nginx/1.18.0

5.1.2 限制HTTP方法

限制允许的HTTP方法可以防止某些类型的攻击,如PUT、DELETE等可能用于上传恶意文件的方法。

配置示例

server {
    # ... 其他配置 ...
    
    location / {
        # 只允许GET、POST和HEAD方法
        limit_except GET POST HEAD {
            deny all;
        }
        
        # ... 其他配置 ...
    }
}

或使用if指令

server {
    # ... 其他配置 ...
    
    if ($request_method !~ ^(GET|POST|HEAD)$) {
        return 405;
    }
    
    # ... 其他配置 ...
}

验证配置

# 测试GET方法(应该成功)
curl -I http://localhost

# 测试PUT方法(应该失败)
curl -I -X PUT http://localhost

5.1.3 防止常见攻击

5.1.3.1 防止点击劫持(X-Frame-Options)

点击劫持是一种通过iframe嵌入恶意网站,诱使用户点击看似合法的按钮来执行恶意操作的攻击方式。

配置示例

server {
    # ... 其他配置 ...
    
    # 防止点击劫持
    add_header X-Frame-Options SAMEORIGIN;
    
    # ... 其他配置 ...
}

X-Frame-Options值说明

  • DENY:不允许任何网站嵌入当前页面
  • SAMEORIGIN:只允许来自同一域名的网站嵌入当前页面
  • ALLOW-FROM https://example.com:只允许来自特定域名的网站嵌入当前页面

5.1.3.2 防止跨站脚本攻击(X-XSS-Protection)

跨站脚本攻击(XSS)是一种通过注入恶意脚本代码来窃取用户数据的攻击方式。

配置示例

server {
    # ... 其他配置 ...
    
    # 防止XSS攻击
    add_header X-XSS-Protection "1; mode=block";
    
    # ... 其他配置 ...
}

5.1.3.3 防止MIME类型嗅探(X-Content-Type-Options)

MIME类型嗅探是浏览器尝试通过分析文件内容来确定文件类型的行为,这可能会导致安全问题。

配置示例

server {
    # ... 其他配置 ...
    
    # 防止MIME类型嗅探
    add_header X-Content-Type-Options nosniff;
    
    # ... 其他配置 ...
}

5.1.3.4 启用严格传输安全(HSTS)

HTTP Strict Transport Security(HSTS)告诉浏览器始终使用HTTPS连接访问网站,防止中间人攻击。

配置示例

server {
    # ... 其他配置 ...
    
    # 启用HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    # ... 其他配置 ...
}

指令说明

  • max-age=31536000:HSTS策略有效期为1年
  • includeSubDomains:HSTS策略适用于所有子域名
  • always:始终添加此头,即使在错误响应中

5.2 SSL/TLS配置

5.2.1 自签名证书生成

在开发和测试环境中,可以使用自签名证书来启用HTTPS。

生成步骤

  1. 生成私钥

    sudo openssl genrsa -out /etc/nginx/ssl/nginx.key 2048
  2. 生成证书签名请求(CSR)

    sudo openssl req -new -key /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.csr

    按照提示输入证书信息,如国家、组织、域名等。

  3. 生成自签名证书

    sudo openssl x509 -req -days 365 -in /etc/nginx/ssl/nginx.csr -signkey /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
  4. 验证证书

    sudo openssl x509 -in /etc/nginx/ssl/nginx.crt -text -noout

5.2.2 Let's Encrypt免费证书

在生产环境中,建议使用Let's Encrypt提供的免费、受信任的SSL证书。

安装Certbot

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx

# CentOS/RHEL
sudo yum install -y epel-release
sudo yum install -y certbot python3-certbot-nginx

获取证书

sudo certbot --nginx -d example.com -d www.example.com

按照提示完成证书获取过程,Certbot会自动更新Nginx配置。

自动续订证书

Let's Encrypt证书的有效期为90天,建议设置自动续订:

# 添加到crontab
sudo crontab -e

添加以下内容:

0 3 * * * certbot renew --quiet

这会在每天凌晨3点检查证书是否需要续订。

5.2.3 HTTPS强制跳转

将所有HTTP请求重定向到HTTPS可以确保网站始终使用加密连接。

配置示例

# HTTP服务器,用于重定向到HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    
    # 301永久重定向到HTTPS
    return 301 https://$server_name$request_uri;
}

# HTTPS服务器
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    # SSL证书配置
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    
    # ... 其他SSL配置 ...
    
    # ... 其他服务器配置 ...
}

5.2.4 性能优化(会话恢复、OCSP装订)

5.2.4.1 SSL会话缓存

启用SSL会话缓存可以减少SSL握手的时间,提高HTTPS连接的性能。

配置示例

http {
    # SSL会话缓存配置
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # ... 其他配置 ...
}

5.2.4.2 OCSP装订

OCSP装订(OCSP Stapling)允许服务器在TLS握手时提供证书的在线证书状态协议(OCSP)响应,减少客户端验证证书的时间。

配置示例

http {
    # OCSP装订配置
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # ... 其他配置 ...
}

验证OCSP装订

openssl s_client -connect localhost:443 -status < /dev/null | grep -A 10 "OCSP response"

5.3 限速与访问控制

5.3.1 连接数限制

限制每个IP的连接数可以防止DoS攻击,避免服务器资源被单个IP耗尽。

配置示例

http {
    # 定义连接数限制区域
    limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
    
    # ... 其他配置 ...
    
    server {
        # ... 其他配置 ...
        
        location / {
            # 限制每个IP的并发连接数为5
            limit_conn conn_limit_per_ip 5;
            
            # ... 其他配置 ...
        }
    }
}

5.3.2 请求速率限制

限制每个IP的请求速率可以防止暴力破解和DoS攻击。

配置示例

http {
    # 定义请求速率限制区域
    limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
    
    # ... 其他配置 ...
    
    server {
        # ... 其他配置 ...
        
        location / {
            # 限制每个IP的请求速率为10次/秒,允许突发10次请求
            limit_req zone=req_limit_per_ip burst=10 nodelay;
            
            # ... 其他配置 ...
        }
    }
}

指令说明

  • rate=10r/s:限制速率为10次请求/秒
  • burst=10:允许突发10次请求
  • nodelay:不延迟突发请求

验证配置

# 使用ab工具测试请求速率限制
ab -n 20 -c 5 http://localhost/

预期输出

  • 部分请求会返回429 Too Many Requests状态码

5.3.3 基于IP/地理位置的访问控制

5.3.3.1 基于IP的访问控制

允许或拒绝特定IP地址或IP段访问网站可以限制访问来源,提高安全性。

配置示例

server {
    # ... 其他配置 ...
    
    # 允许特定IP访问,拒绝其他所有IP
    location /admin {
        allow 192.168.1.100;
        allow 10.0.0.0/24;
        deny all;
        
        # ... 其他配置 ...
    }
    
    # ... 其他配置 ...
}

或使用deny指令

server {
    # ... 其他配置 ...
    
    # 拒绝特定IP访问,允许其他所有IP
    location / {
        deny 192.168.1.200;
        allow all;
        
        # ... 其他配置 ...
    }
    
    # ... 其他配置 ...
}

5.3.3.2 基于地理位置的访问控制

使用ngx_http_geoip_module模块可以基于IP的地理位置进行访问控制,需要安装GeoIP数据库。

配置示例

http {
    # 加载GeoIP数据库
    geoip_country /usr/share/GeoIP/GeoIP.dat;
    
    # 定义允许访问的国家
    map $geoip_country_code $allowed_country {
        default no;
        CN yes;
        US yes;
    }
    
    # ... 其他配置 ...
    
    server {
        # ... 其他配置 ...
        
        # 只允许来自中国和美国的访问
        if ($allowed_country = no) {
            return 403;
        }
        
        # ... 其他配置 ...
    }
}

安装GeoIP数据库

# Ubuntu/Debian
sudo apt-get install -y geoip-database

# CentOS/RHEL
sudo yum install -y geoip

5.4 实战项目:配置安全的Nginx服务器

在这个实战项目中,我们将配置一个安全的Nginx服务器,包含以下功能:

  1. 隐藏Nginx版本信息
  2. 限制HTTP方法
  3. 防止常见攻击
  4. 配置HTTPS(使用自签名证书)
  5. 实现HTTPS强制跳转
  6. 配置SSL会话缓存和OCSP装订
  7. 限制连接数和请求速率
  8. 基于IP的访问控制

5.4.1 项目准备

1. 创建SSL证书目录

sudo mkdir -p /etc/nginx/ssl

2. 生成自签名证书

sudo openssl genrsa -out /etc/nginx/ssl/nginx.key 2048
sudo openssl req -new -key /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.csr -subj "/CN=localhost/O=Test Org/C=CN"
sudo openssl x509 -req -days 365 -in /etc/nginx/ssl/nginx.csr -signkey /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

5.4.2 配置Nginx

1. 创建Nginx配置文件

sudo nano /etc/nginx/conf.d/secure-nginx.conf

2. 添加以下配置

http {
    # 隐藏Nginx版本信息
    server_tokens off;
    
    # SSL会话缓存配置
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # OCSP装订配置
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # 连接数限制区域
    limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
    
    # 请求速率限制区域
    limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
    
    # HTTP服务器,用于重定向到HTTPS
    server {
        listen 80;
        server_name localhost;
        
        # 301永久重定向到HTTPS
        return 301 https://$server_name$request_uri;
    }
    
    # HTTPS服务器
    server {
        listen 443 ssl http2;
        server_name localhost;
        
        # SSL证书配置
        ssl_certificate /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key /etc/nginx/ssl/nginx.key;
        
        # 现代SSL配置
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
        ssl_prefer_server_ciphers off;
        
        # 安全头配置
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options nosniff;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        
        # 只允许GET、POST和HEAD方法
        if ($request_method !~ ^(GET|POST|HEAD)$) {
            return 405;
        }
        
        location / {
            root /var/www/html;
            index index.html;
            
            # 限制连接数和请求速率
            limit_conn conn_limit_per_ip 5;
            limit_req zone=req_limit_per_ip burst=10 nodelay;
        }
        
        # 管理界面,只允许特定IP访问
        location /admin {
            root /var/www/html;
            index admin.html;
            
            # 只允许本地访问
            allow 127.0.0.1;
            deny all;
        }
    }
}

5.4.3 验证配置

1. 测试配置语法

sudo nginx -t

2. 重载Nginx配置

sudo systemctl reload nginx

3. 验证HTTPS访问

# 测试HTTP到HTTPS的重定向
curl -I http://localhost

# 测试HTTPS访问
curl -k -I https://localhost

4. 验证安全头

curl -k -I https://localhost | grep -E "X-Frame-Options|X-XSS-Protection|X-Content-Type-Options|Strict-Transport-Security"

5. 验证版本信息隐藏

curl -k -I https://localhost | grep "Server"

6. 测试访问控制

# 测试管理界面访问(应该成功,因为是本地访问)
curl -k https://localhost/admin

# 使用其他IP测试管理界面访问(应该失败)
curl -k -H "X-Forwarded-For: 192.168.1.100" https://localhost/admin

5.4.4 常见问题与解决方案

问题1:SSL证书验证失败

解决方案

  1. 确保证书文件路径正确

  2. 确保证书和私钥匹配:

    openssl x509 -noout -modulus -in /etc/nginx/ssl/nginx.crt | openssl md5
    openssl rsa -noout -modulus -in /etc/nginx/ssl/nginx.key | openssl md5

    两个命令的输出应该相同

  3. 对于自签名证书,使用curl -k或在浏览器中添加例外

问题2:访问控制不生效

解决方案

  1. 检查allow/deny指令的顺序,先allow后deny
  2. 检查IP地址是否正确
  3. 如果使用了代理,确保获取真实客户端IP:
    set_real_ip_from 192.168.1.0/24;
    real_ip_header X-Forwarded-For;

问题3:限速不生效

解决方案

  1. 确保已正确定义limit_conn_zone或limit_req_zone
  2. 确保limit_conn或limit_req指令在正确的位置
  3. 检查是否超过了限制的阈值

章节总结

在本章中,我们学习了:

  1. 基础安全配置

    • 隐藏Nginx版本信息
    • 限制HTTP方法
    • 防止常见攻击(点击劫持、XSS、MIME类型嗅探)
    • 启用严格传输安全
  2. SSL/TLS配置

    • 生成自签名证书
    • 获取Let's Encrypt免费证书
    • 实现HTTPS强制跳转
    • 优化SSL性能(会话缓存、OCSP装订)
  3. 限速与访问控制

    • 限制连接数
    • 限制请求速率
    • 基于IP的访问控制
    • 基于地理位置的访问控制
  4. 实战项目

    • 配置安全的Nginx服务器
    • 验证安全配置
    • 解决常见问题

实践练习

  1. 隐藏Nginx版本信息
  2. 配置HTTPS,使用自签名证书
  3. 实现HTTP到HTTPS的强制跳转
  4. 配置请求速率限制,限制每个IP每秒10次请求
  5. 配置基于IP的访问控制,只允许特定IP访问管理界面
  6. 添加安全头,防止常见攻击

延伸阅读


下一章第6章:动态内容处理

« 上一篇 反向代理与负载均衡 下一篇 » 动态内容处理