暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

NG配置中的X-Forwarded-For请求头

乔克的好奇心 2019-06-05
1836

PS:图片来自网络


    要放端午了,提前祝大家假期愉快,多吃粽子。

    

    前因:公司同事说明明在NG里配置了X-Forwarded-For,而且日志格式里也配置了$http_x_forwarded_for,为什么在NG的日志里打印出来是“-”(也就是空的),是不是配置问题?


     排查:登录NG服务器,分别在前置NG和内置NG上查看配置,确定配置没有问题,在前置NG上查看access.log,$http_x_forwarded_for字段打印出来确实为空,不过在内置NG上是能够正常打印出日志的,这是为什么呢?


    原来......在很久很久以前......

PS:图片来自网络

一、简述

我们在做nginx方向代理的时候,为了记录整个代理过程,我们往往会在配置文件中加上如下配置:

  1. location ^~ /app/download/ {

  2. ...

  3. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  4. ...

  5. proxy_pass http://10.1.10.203:8080;

  6. }

复制

proxy_set_header这段代码就是记录整个代理过程的配置。其中X-Forwarded-For(XFF)位于HTTP请求头,目前来说已经成为事实上的标准。


XFF的请求格式很简单,如下:

  1. X-Forwarded-For: client, proxy1, proxy2

复制

由上面可以看到XFF的的内容由[IP+英文逗号+空格]组成(如果有多个代理的话),最开始的client是客户端的IP,proxy1和proxy2分别是一级代理和二级代理的IP。
假设代理如下:

如上,proxy1、proxy2和proxy3都用NG做反代,并且在它们的配置上都加上如下配置:

  1. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

复制

那么在Real Server(NG的WEB容器)上打印的日志(日志里带$httpxforwarded_for)就会带有IP0,IP1,IP2的HTTP头,可以看到没有IP3,因为IP3是直连服务器,它会给XFF追加IP2的地址,表示它是帮proxy2做转发的,Real Server要获取IP3的地址,需通过remote Address字段获得。
同理,在proxy3上日志里只会有IP0和IP1,proxy2上日志里只有IP0,proxy1上没有IP。


明白了没?

没明白没关系,做实验就对了......


二、测试

测试拓扑如下:

在proxy1上的配置如下:

  1. server {

  2. listen 80 default_server;

  3. listen [::]:80 default_server;

  4. server_name _;

  5. root /usr/share/nginx/html;


  6. # Load configuration files for the default server block.

  7. include /etc/nginx/default.d/*.conf;


  8. location {

  9. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  10. proxy_pass http://192.168.169.130/;

  11. }

  12. }

复制

在proxy2上的配置如下:

  1. server {

  2. listen 80 default_server;

  3. listen [::]:80 default_server;

  4. server_name _;

  5. root /usr/share/nginx/html;


  6. # Load configuration files for the default server block.

  7. include /etc/nginx/default.d/*.conf;


  8. location {

  9. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  10. proxy_pass http://192.168.169.131/;

  11. }

  12. }

复制

在proxy3的配置如下:

  1. server {

  2. listen 80 default_server;

  3. listen [::]:80 default_server;

  4. server_name _;

  5. root /usr/share/nginx/html;


  6. # Load configuration files for the default server block.

  7. include /etc/nginx/default.d/*.conf;


  8. location / {

  9. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  10. proxy_pass http://xxx.xxx.xxx.xxx:8888/;

  11. }

  12. }

复制

proxy1,proxy2,proxy3上的日志格式如下:

  1. log_format main '$remote_addr - $remote_user [$time_local] "$request" '

  2. '$status $body_bytes_sent "$http_referer" '

  3. '"$http_user_agent" "$http_x_forwarded_for"';

复制

Real Server日志格式如下:

  1. log_format main '$remote_addr - $remote_user [$time_local] "$request" '

  2. '$status $body_bytes_sent $upstream_cache_status "$http_referer" '

  3. '"$http_user_agent" "==$http_x_forwarded_for" "--$http_x_real_ipi"';

复制

配置完成后,我在本机浏览器输入:http://192.168.169.128/,然后分别在proxy1-3还有Real Server上抓取nginx日志,proxy1-3日志最后一个字段是$httpxforwardedfor,Real Server倒数二个字段是$httpxforwardedfor如下:
proxy1日志:

  1. 192.168.169.1 - - [04/Jun/2019:10:57:06 +0800] "GET / HTTP/1.1" 200 20 "-"

  2. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)

  3. Chrome/74.0.3729.169 Safari/537.36" "-"

复制

proxy2日志:

  1. 192.168.169.128 - - [04/Jun/2019:10:57:06 +0800] "GET / HTTP/1.0" 200 10 "-"

  2. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)

  3. Chrome/74.0.3729.169 Safari/537.36" "192.168.169.1"

复制

proxy3日志:

  1. 192.168.169.130 - - [29/Mar/2019:23:29:36 +0800] "GET / HTTP/1.0" 200 10 "-"

  2. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)

  3. Chrome/74.0.3729.169 Safari/537.36" "192.168.169.1, 192.168.169.128"

复制

Real Server日志:

  1. 183.66.224.50 - - [04/Jun/2019:10:57:03 +0800] "GET / HTTP/1.0" 200 10 - "-"

  2. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)

  3. Chrome/74.0.3729.169 Safari/537.36" "==192.168.169.1, 192.168.169.128, 192.168.169.130" "---"

复制

看出点什么没有?

我们可以看到,在proxy1的日志里并没有获得IP,在proxy2的日志里打印出了"192.168.169.1"(之所以是这个地址,是因为我是本地虚拟机,做的NAT转发),在proxy3的日志里打印出"192.168.169.1, 192.168.169.128",在Real-Server上打印出了192.168.169.1, 192.168.169.128, 192.168.169.130"。是不是和我上面说的一样的?在proxy1上,proxy1和client直连,它会在HTTP头上加client的IP,但是并不会打印出来,它只是告诉后面它是帮client做转发的,后面的依次类推。

小总结一波:
(1)、设置X-Forwarded-For是一个可叠加的过程;
(2)、后端服务器XFF获取不到直连服务器IP。比如Real-Server的日志中XFF字段没有proxy3的IP地址,依次类推;
(3)、代理中要配置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

当然,如果要打印直连的IP怎么办呢?可以用$remote_addr(可以自行研究一哈)。

好了,现在应该懂了吧?不懂?没关系,知道就行

PS:图片来自网络

---------------------------------------------------------------------------

<-欢迎大佬们转载和点“在看”,同时欢迎分享!->

文章转载自乔克的好奇心,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论