nginx 如何禁用 "Host" 校验?

目前有个嵌入式设备,发出的http请求是不标准的

POST /dev_heart_info HTTP/1.1
Host: Host /HTTP/1.0
User-Agent: My Device
Connection: Keep-Alive
accept: application/json
content-type: application/json;charset=UTF-8
Content-Length: 95

{
    "devId":    "FS4051-C21SJ30A4900",
    "moduleId":    0,
    "msgType":    4106,
    "devIp":    "192.168.8.52"
}HTTP/1.1 400 Bad Request
Server: nginx/1.21.5
Date: Fri, 28 Oct 2022 11:19:37 GMT
Content-Type: text/html
Content-Length: 157
Connection: close

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.21.5</center>
</body>
</html>

请求过来的header中的host字段不标准,所以nginx不做解析和转发直接报400了。
想请教下这种情况如何处理,禁用Host校验或者nginx重设掉该Host均可。

最后看了nginx源码发现确实是强制不支持了,最后解决方案是自己修改了那段代码,自己编译nginx,这里把步骤给后来人参考下

  1. 下载nginx源码
wget http://nginx.org/download/nginx-1.21.5.tar.gz
  1. 修改检测Host的函数,文件ngx_http_request.c
static ngx_int_t
ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
{
    return NGX_OK;
}

改为直接return正常

  1. 构建nginx镜像,Dockerfile如下
FROM centos:7.8.2003

MAINTAINER wudengguang (wu_dengguang@finsung.com)

ADD nginx-1.21.5 /usr/local/src/nginx-1.21.5
WORKDIR /usr/local/src/nginx-1.21.5

RUN yum install -y gcc gcc-c++  glibc make autoconf openssl openssl-devel \
&& yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel \
&& useradd -M -s /sbin/nologin nginx && BUILD_CONFIG="--prefix=/usr/local/nginx \
        --http-client-body-temp-path=/var/cache/nginx/client_temp \
        --http-proxy-temp-path=/var/cache/nginx/proxy_temp \
        --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
        --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
        --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
        --with-http_stub_status_module \
        --with-http_ssl_module \
        --with-stream \
        --with-http_v2_module \
        --with-threads" && ./configure $BUILD_CONFIG \
&& mkdir -p /var/cache/nginx && make && make install


ENV PATH /usr/local/nginx/sbin:$PATH

EXPOSE 80
EXPOSE 443

ENTRYPOINT ["nginx"]

CMD ["-g","daemon off;"]
阅读 4.1k
2 个回答

我用nginx验证了一下,找了资料,发现nginx似乎没办法处理这个非法的Host。
但是我用haproxy测试了一下,haproxy可以正常处理非法的host,重写host之后可以正常传给后端。

haproxy配置:

listen http-in
        mode http
        bind *:80
        http-request replace-value Host (.*) localhost
        server server1 127.0.0.1:8000

这里我把Host 替换成了 localhost

===
处理之后,后端接收到的请求是这样的:

POST /dev_heart_info HTTP/1.1
host: localhost
user-agent: My Device
accept: application/json
content-type: application/json;charset=UTF-8
content-length: 1

1

要是不方便更新终端的话,可以考虑在nginx前面再套一个haproxy,让haproxy处理后再转给nginx或者后端服务。

一般用server_name指令指定空字符串或者干脆删掉(因为默认就是空字符串),应该就不会校验Host内容了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题