1. 博客/

nginx请求头X-Real-IP与X-Forwarded-For

·455 字·3 分钟
Nginx

前言
#

nginx反向代理后端应用服务器时,遇到web应用服务器需要获取客户端真实IP,该如何正确配置nginx?本文分别在一级反向代理及两级反向代理情况下,测试请求头X-Real-IP与X-Forwarded-For如何配置

一级代理测试验证
#

1.测试架构: nginx反向代理 + tomcat web服务

ipserverserver port
192.168.196.135nginx31005
192.168.196.136tomcat31001
192.168.196.1客户端-

2.部署tomcat测试war包

$cat test.jsp
 <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
      pageEncoding="ISO-8859-1"%>
 <%
 out.println("Protocol: " + request.getProtocol());  
 out.println("Server Name: " + request.getServerName());  
 out.println("Server Port: " + request.getServerPort());  
 out.println("Remote Addr: " + request.getRemoteAddr());  
 out.println("Remote Host: " + request.getRemoteHost());  
 out.println("Request URL: " + request.getRequestURL());  
 out.println("Host: " + request.getHeader("Host"));  
 out.println("X-Real-IP: " + request.getHeader("X-Real-IP"));
 out.println("X-Forwarded-For: " + request.getHeader("X-Forwarded-For"));
 out.println("Connection : " + request.getHeader("Connection"));  
 %>
  
$jar cvf th.war th/test.jsp

3.修改nginx.conf

upstream backendsrv {
    server 192.168.196.136:31005;
}
server {
    listen       31001;
    server_name  www.test.com;
    location /th {
        root   html;
        index  index.html index.htm;
        proxy_pass http://backendsrv;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

nginx重设请求头X-Real-IP为$remote_addr、 X-Forwarded-For为$proxy_add_x_forwarded_for

$proxy_add_x_forwarded_for:

$remote_addr变量值添加在客户端“X-Forwarded-For”请求头的后面,并以逗号分隔。 如果客户端请求未携带“X-Forwarded-For”请求头,$proxy_add_x_forwarded_for 变量值将与$remote_addr变量相同

4.使用curl构造X-Real-IP、X-Forwarded-For请求头,在客户端发起请求

$curl -H "X-Forwarded-For: 1.1.1.1" -H "X-Real-IP: 2.2.2.2" 192.168.196.135:31001/th/test.jsp
Protocol: HTTP/1.0
Server Name: 192.168.196.135
Server Port: 31001
Remote Addr: 192.168.196.135
Remote Host: 192.168.196.135
Request URL: http://192.168.196.135:31001/th/test.jsp
Host: 192.168.196.135:31001
X-Real-IP: 192.168.196.1
X-Forwarded-For: 1.1.1.1, 192.168.196.1
Connection : close

根据请求结果看出:

  • nginx清理了伪造的X-Real-IP请求头并重写为clientIP-
  • nginx在X-Forwarded-For后追加clientIP

后端web应用可通过X-Real-IP或者X-Forwarded-For的最后一个IP获取clientIP

5.本例中,nginx为一级代理,为避免客户端伪造X-Forwarded-For请求头,可添加 proxy_set_header X-Forwarded-For $remote_addr

upstream backendsrv {
    server 192.168.196.136:31005;
}
server {
    listen       31001;
    server_name  www.test.com;
    location /th {
        root   html;
        index  index.html index.htm;
        proxy_pass http://backendsrv;
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

$curl -H "X-Forwarded-For: 1.1.1.1" 192.168.196.135:31001/th/test.jsp
Protocol: HTTP/1.0
Server Name: 192.168.196.135
Server Port: 31001
Remote Addr: 192.168.196.135
Remote Host: 192.168.196.135
Request URL: http://192.168.196.135:31001/th/test.jsp
Host: 192.168.196.135:31001
X-Real-IP: 192.168.196.1
X-Forwarded-For: 192.168.196.1
Connection : close

二级代理测试验证
#

1.测试架构: nginx1反向代理 +nginx2反向代理+ tomcat web服务

ipserverserver port
192.168.196.133nginx131009
192.168.196.135nginx231001
192.168.196.136tomcat31005
192.168.196.1client-

2.修改nginx.conf

一级反向代理nginx1
upstream backendnginx {
    server 192.168.196.135:31001;
}
server {
    listen       31009;
    server_name  192.168.196.133;
    location /th {
        root   html;
        index  index.html index.htm;
        proxy_pass http://backendnginx;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

二级反向代理nginx2
upstream backendsrv {
    server 192.168.196.136:31005;
}
server {
    listen       31001;
    server_name  www.test.com;
    location /th/ft {
        root   html;
        index  index.html index.htm;
        proxy_pass http://backendsrv;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

3.使用curl构造X-Forwarded-For请求头,在客户端发起请求

$curl -H "X-Forwarded-For: unknown, 1.1.1.1" 192.168.196.133:31009/th/ft/test.jsp
Protocol: HTTP/1.0
Server Name: 192.168.196.133
Server Port: 31009
Remote Addr: 192.168.196.135
Remote Host: 192.168.196.135
Request URL: http://192.168.196.133:31009/th/ft/test.jsp
Host: 192.168.196.133:31009
X-Real-IP: 192.168.196.1
X-Forwarded-For: unknown, 1.1.1.1, 192.168.196.1, 192.168.196.133
Connection : close

nginx依次将$remote_addr追加到X-Forwarded-For

clientIP为倒数第n个IP, n为proxy的次数

4.面向客户端的第一级nginx中,添加proxy_set_header X-Forwarded-For $remote_addr;

upstream backendnginx {
    server 192.168.196.135:31001;
}
server {
    listen       31009;
    server_name  192.168.196.133;
    location /th {
        root   html;
        index  index.html index.htm;
        proxy_pass http://backendnginx;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

$curl -H "X-Forwarded-For: unknown, 1.1.1.1"  192.168.196.133:31009/th/ft/test.jsp

Protocol: HTTP/1.0
Server Name: 192.168.196.133
Server Port: 31009
Remote Addr: 192.168.196.135
Remote Host: 192.168.196.135
Request URL: http://192.168.196.133:31009/th/ft/test.jsp
Host: 192.168.196.133:31009
X-Real-IP: 192.168.196.1
X-Forwarded-For: 192.168.196.1, unknown, 1.1.1.1, 192.168.196.1, 192.168.196.133
Connection : close

X-Forwarded-For的第一个IP为clientIP

最佳实践
#

第一级反向代理nginx: proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

中间的反向代理nginx只需配置: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Related

Nginx请求头proxy_set_header
·229 字·2 分钟
Nginx
P2P文件与镜像分发开源解决方案Dragonfly安装部署
·859 字·5 分钟
Docker