You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何模拟并阻断HTTP_HOST伪造攻击?Nginx反向代理问题排查

问题解决:伪造Host请求绕过Nginx到后端Django的处理方案

一、正确的攻击模拟方法

根据你的场景,请求能绕过Nginx直接到达Django,大概率是两种情况,对应模拟方式如下:

1. 直接访问后端Django服务端口(未被防火墙限制)

如果你的Django服务监听的端口(如8000)对外网开放,攻击者可直接绕过Nginx连接该端口,伪造Host头触发报错:

curl -H "Host: fake-domain.example" http://你的服务器IP:8000

这种情况下,请求完全不经过Nginx,自然不会被默认server块拦截。

2. Nginx未覆盖HTTP/HTTPS全场景的默认规则

如果你的默认server块只配置了HTTPS,而HTTP协议的默认server未做处理,攻击者可通过HTTP请求伪造Host,可能被Nginx转发到后端:

curl -H "Host: fake-domain.example" http://你的服务器IP

或者针对HTTPS场景,若默认server块未正确配置SSL证书(比如缺少ssl_certificate/ssl_certificate_key),部分客户端可能绕过SNI验证发起请求:

curl --insecure -H "Host: fake-domain.example" https://你的服务器IP

二、Nginx防护修复方案

1. 防火墙隔离后端服务

首先确保Django服务仅允许Nginx本地访问,禁止外网直接连接:

# 允许本地IP访问Django端口(假设为8000)
ufw allow from 127.0.0.1 to any port 8000
# 拒绝其他来源访问该端口
ufw deny 8000
# 重启防火墙生效
ufw reload

2. 完善Nginx默认Server块(覆盖HTTP+HTTPS)

HTTP默认Server块(拦截所有非法HTTP请求)

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 444; # 直接关闭连接,无响应
}

HTTPS默认Server块(拦截所有非法HTTPS请求)

注意:需要配置可用的SSL证书(可使用Certbot生成的默认证书,或自签名证书)

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    server_name _;

    # 使用Certbot生成的默认证书路径(Ubuntu 20.04下)
    ssl_certificate /etc/letsencrypt/live/你的主域名/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/你的主域名/privkey.pem;

    # 直接关闭非法请求连接
    return 444;
}

3. 强制验证合法Host后再转发后端

在每个对应合法域名的Server块中,添加Host验证规则,仅允许指定域名的请求转发到Django:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name your-valid-domain1.com;

    # Certbot生成的SSL配置
    ssl_certificate /etc/letsencrypt/live/your-valid-domain1.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-valid-domain1.com/privkey.pem;

    # 验证Host合法性,非法则直接拒绝
    if ($host !~* ^your-valid-domain1.com$) {
        return 444;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 添加X-Forwarded-Proto头,让Django识别HTTPS请求
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

也可通过map指令统一管理所有合法Host,简化配置:

http {
    map $host $allowed_host {
        default 0;
        your-valid-domain1.com 1;
        your-valid-domain2.com 1;
    }

    # 然后在每个Server块中添加:
    if ($allowed_host = 0) {
        return 444;
    }
}

4. 确认请求强制走HTTPS

在HTTP Server块中,将所有请求重定向到HTTPS(仅针对合法域名,非法请求直接返回444):

server {
    listen 80;
    listen [::]:80;

    # 合法域名重定向到HTTPS
    server_name your-valid-domain1.com your-valid-domain2.com;
    return 301 https://$host$request_uri;

    # 非法域名直接拒绝
    server_name _;
    return 444;
}

同时在Django的settings.py中配置,确保识别Nginx转发的HTTPS请求:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

5. Django层面二次加固

虽然Nginx应拦截所有非法请求,但仍需确保Django的ALLOWED_HOSTS严格配置:

ALLOWED_HOSTS = ['your-valid-domain1.com', 'your-valid-domain2.com']

避免使用通配符,同时确保DEBUG = False(生产环境必须关闭)。

内容的提问来源于stack exchange,提问作者Kaustubh Bhalerao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:05:45