HTTP协议头中X-Forwarded-For是能做什么?

X-Forwarded-For和相关几个头部的理解

  • $remote_addr

    是nginx与客户端进行TCP连接过程中,获得的客户端真实地址. Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求

  • X-Real-IP

    是一个自定义头。X-Real-Ip 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。需要注意的是,X-Real-Ip 目前并不属于任何标准,代理和 Web 应用之间可以约定用任何自定义头来传递这个信息

  • X-Forwarded-For

    X-Forwarded-For 是一个扩展头。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP,现在已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中.

X-Forwarded-For请求头格式非常简单,就这样:

X-Forwarded-For:client, proxy1, proxy2

可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。

如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:

X-Forwarded-For: IP0, IP1, IP2

Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 remote_address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。

详细分析一下,这样的结果是经过这样的流程而形成的:

  1. 用户IP0—> 代理Proxy1(IP1),Proxy1记录用户IP0,并将请求转发个Proxy2时,带上一个Http Header X-Forwarded-For: IP0

  2. Proxy2收到请求后读取到请求有 X-Forwarded-For: IP0,然后proxy2 继续把链接上来的proxy1 ip追加到 X-Forwarded-For 上面,构造出X-Forwarded-For: IP0, IP1,继续转发请求给Proxy 3

  3. 同理,Proxy3 按照第二部构造出 X-Forwarded-For: IP0, IP1, IP2,转发给真正的服务器,比如NGINX,nginx收到了http请求,里面就是 X-Forwarded-For: IP0, IP1, IP2 这样的结果。所以Proxy 3 的IP3,不会出现在这里。

  4. nginx 获取proxy3的IP 能通过remote_address就是真正建立TCP链接的IP,这个不能伪造,是直接产生链接的IP。$remote_address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。

x-forwarded-for 实践研究:

  1. uwsgi_pass的情况下,nginx 没有设置proxy_pass x-forwarded-for: $proxy_add_x_forwarded_for;

    • 如果请求头传了XFF,在flask里面能正常读取请求头里面的XFF,就是当是一个普通的头读出;如果header不传这个XFF的话,就读不到
  2. proxy_pass 情况下

    • 没有传 # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for 的话,跟上面的uwsgi_pass 一样,都是在没有设置header XFF情况下,读不到。

    • 如果传了 proxy_set_header X-Forwarded-For remote_address),因为这句proxy_set_header 会让nginx追加一个$remote_address到XFF。

    • header 传xff的话, 程序里面可以读到Xff 头: X-Forwarded-For: 188.103.19.120, 10.0.2.2 (第一个是我自己编的,第二个是proxy_add_x_forwarded_for 这句而追加$remote_addr到XFF。

总结:

  1. 只要nginx前端(例如lvs, varnish)转发请求给nginx的时候,带了x-forwarded-for ,那么程序就一定能读到这个字段,如果nginx还设置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for, 那么程序能读到XFF是:ip0, ip1 (客户端Ip,lvs或者varnishIP)。 如果nginx没有设置,那么nginx还是会原样把http头传给程序,也就是说程序也能读到XFF,而且XFF就是ip0 客户端IP。

  2. proxy_pass 设置这个头 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 是站在一个作为代理的角度把。能继续传输多级代理的头。

  3. nginx的日志格式写了$http_x_forwared_for 说明前端(lvs)确实传了这个头过来。所以是程序是读取到的

  4. uwsgi_pass 不能设置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 这个头,是因为这个头是对http代理来说,用来传递IP的,uwsgi 不可能充当一个代理。

  5. nginx->程序,这里其实有两个链接过程,其他IP与nginx的TCP连接, nginx与程序的TCP连接。所以$remote_addr都是对各自来说的。程序的remote_addr: remote_addr 127.0.0.1 (跟它链接的是nginx 内网127.0.0.1)nginx的remote_addr : X-Real-Ip: 10.0.2.2 (跟它链接的是我的电脑,IP 10.0.2.2)

  6. 对程序来说,读取的request.remote_addr 也永远是直接跟他链接的ip, 也就是反向代理nginx

  7. The access_route attribute uses the X-Forwarded-For header, falling back to the REMOTE_ADDRWSGI variable; 也就是说access_route默认读取XFF头,如果没有,降级读取WSGI的REMOTE_ADDR变量,这个 WSGI的REMOTE_ADDR变量 就是 $remote_addr

  8. request.envron 是WSGI的变量,都是wsgi server转过来的,普通的头都是加了HTTP_前缀的 ,包括proxy_set_header Host proxy_add_x_forwarded_for;
    添加的头都会出现在处理,因为他们就是普通的http头

  9. LVS->nginx的情况下, 请求的时候主动加XFF,程序读取的时候没显示。因为LVS设置XFF的时候,直接把直连的IP赋值给LVS,忽略掉所有本来有的XFF,要从LVS这里开始。 所以程序读到的XFF是 :XFF headers 218.107.55.254, 10.120.214.252
    前面的是我的IP, 后面的是LVS的IP

X-Forwarded-For和相关几个头部的理解

  • $remote_addr

    是nginx与客户端进行TCP连接过程中,获得的客户端真实地址. Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求

  • X-Real-IP

    是一个自定义头。X-Real-Ip 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。需要注意的是,X-Real-Ip 目前并不属于任何标准,代理和 Web 应用之间可以约定用任何自定义头来传递这个信息

  • X-Forwarded-For

    X-Forwarded-For 是一个扩展头。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP,现在已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中.

X-Forwarded-For请求头格式非常简单,就这样:

X-Forwarded-For:client, proxy1, proxy2

可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。

如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:

X-Forwarded-For: IP0, IP1, IP2

Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 remote_address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。

详细分析一下,这样的结果是经过这样的流程而形成的:

  1. 用户IP0—> 代理Proxy1(IP1),Proxy1记录用户IP0,并将请求转发个Proxy2时,带上一个Http Header X-Forwarded-For: IP0

  2. Proxy2收到请求后读取到请求有 X-Forwarded-For: IP0,然后proxy2 继续把链接上来的proxy1 ip追加到 X-Forwarded-For 上面,构造出X-Forwarded-For: IP0, IP1,继续转发请求给Proxy 3

  3. 同理,Proxy3 按照第二部构造出 X-Forwarded-For: IP0, IP1, IP2,转发给真正的服务器,比如NGINX,nginx收到了http请求,里面就是 X-Forwarded-For: IP0, IP1, IP2 这样的结果。所以Proxy 3 的IP3,不会出现在这里。

  4. nginx 获取proxy3的IP 能通过remote_address就是真正建立TCP链接的IP,这个不能伪造,是直接产生链接的IP。$remote_address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。

x-forwarded-for 实践研究:

  1. uwsgi_pass的情况下,nginx 没有设置proxy_pass x-forwarded-for: $proxy_add_x_forwarded_for;

    • 如果请求头传了XFF,在flask里面能正常读取请求头里面的XFF,就是当是一个普通的头读出;如果header不传这个XFF的话,就读不到
  2. proxy_pass 情况下

    • 没有传 # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for 的话,跟上面的uwsgi_pass 一样,都是在没有设置header XFF情况下,读不到。

    • 如果传了 proxy_set_header X-Forwarded-For remote_address),因为这句proxy_set_header 会让nginx追加一个$remote_address到XFF。

    • header 传xff的话, 程序里面可以读到Xff 头: X-Forwarded-For: 188.103.19.120, 10.0.2.2 (第一个是我自己编的,第二个是proxy_add_x_forwarded_for 这句而追加$remote_addr到XFF。

总结:

  1. 只要nginx前端(例如lvs, varnish)转发请求给nginx的时候,带了x-forwarded-for ,那么程序就一定能读到这个字段,如果nginx还设置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for, 那么程序能读到XFF是:ip0, ip1 (客户端Ip,lvs或者varnishIP)。 如果nginx没有设置,那么nginx还是会原样把http头传给程序,也就是说程序也能读到XFF,而且XFF就是ip0 客户端IP。

  2. proxy_pass 设置这个头 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 是站在一个作为代理的角度把。能继续传输多级代理的头。

  3. nginx的日志格式写了$http_x_forwared_for 说明前端(lvs)确实传了这个头过来。所以是程序是读取到的

  4. uwsgi_pass 不能设置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 这个头,是因为这个头是对http代理来说,用来传递IP的,uwsgi 不可能充当一个代理。

  5. nginx->程序,这里其实有两个链接过程,其他IP与nginx的TCP连接, nginx与程序的TCP连接。所以$remote_addr都是对各自来说的。程序的remote_addr: remote_addr 127.0.0.1 (跟它链接的是nginx 内网127.0.0.1)nginx的remote_addr : X-Real-Ip: 10.0.2.2 (跟它链接的是我的电脑,IP 10.0.2.2)

  6. 对程序来说,读取的request.remote_addr 也永远是直接跟他链接的ip, 也就是反向代理nginx

  7. The access_route attribute uses the X-Forwarded-For header, falling back to the REMOTE_ADDRWSGI variable; 也就是说access_route默认读取XFF头,如果没有,降级读取WSGI的REMOTE_ADDR变量,这个 WSGI的REMOTE_ADDR变量 就是 $remote_addr

  8. request.envron 是WSGI的变量,都是wsgi server转过来的,普通的头都是加了HTTP_前缀的 ,包括proxy_set_header Host proxy_add_x_forwarded_for;
    添加的头都会出现在处理,因为他们就是普通的http头

  9. LVS->nginx的情况下, 请求的时候主动加XFF,程序读取的时候没显示。因为LVS设置XFF的时候,直接把直连的IP赋值给LVS,忽略掉所有本来有的XFF,要从LVS这里开始。 所以程序读到的XFF是 :XFF headers 218.107.55.254, 10.120.214.252
    前面的是我的IP, 后面的是LVS的IP

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/37794.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript 的 属性、方法、事件

使用 javascript 设计一个学生类、(属性:ID、姓名、性别,方法:学习、休息、,事件:上学、放学、上课、下课)学校有定时器每1秒钟触发一次时钟事件,每节课45分钟,课间15分钟 var Stud…

13. Lammps入门in文件简介-1

来源: “码农不会写诗”公众号 链接:Lammps入门in文件简介-1 文章目录 01 in文件简介02 in文件命令解析规则 书回正文 Lammps通过一次一行地从输入脚本(文本文件,通常称in文件)中读取命令来执行计算,当输入…

7-1作业

1.实验目的:完成字符收发 led.h #ifndef __GPIO_H__ #define __GPIO_H__#include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_uart.h"//RCC,GPIO,UART初始化 void init();//字符数据发送 void set_tt…

Web端登录页和注册页源码

前言&#xff1a;登录页面是前端开发中最常见的页面&#xff0c;下面是登录页面效果图和源代码&#xff0c;CV大法直接拿走。 1、登录页面 源代码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>登录</ti…

Django 和 Django REST framework 创建对外 API

1. 环境准备 确保你已经安装了 Python 和 Django。如果尚未安装 Django REST framework&#xff0c;通过 pip 安装它&#xff1a; pip install djangorestframework 2. 创建 Django 项目 如果你还没有 Django 项目&#xff0c;可以通过以下命令创建&#xff1a; django-ad…

每日复盘-20240701

今日关注&#xff1a; 20240701 六日涨幅最大: ------1--------301182--------- 凯旺科技 五日涨幅最大: ------1--------300977--------- 深圳瑞捷 四日涨幅最大: ------1--------300977--------- 深圳瑞捷 三日涨幅最大: ------1--------300461--------- 田中精机 二日涨幅最…

Lua实现链表(面向对象应用)

Lua实现面向对象 面向对象核心三要素Lua面向对象大致原理面向对象示例继承与多态示例 面向对象核心三要素 1.封装&#xff1a;对一个事物的抽象为一些属性和行为动作的集合&#xff0c;封装将属性和行为动作&#xff08;操作数据的方法&#xff09;绑定在一起&#xff0c;并隐藏…

快钱支付股东全部股权已被质押!

根据近期工商信息&#xff0c;第三方支付机构快钱支付清算信息有限公司&#xff08;简称“快钱支付”&#xff09;实际控股方快钱金融服务&#xff08;上海&#xff09;有限公司&#xff08;简称“快钱金融”&#xff09;&#xff0c;作为出质股权标的企业&#xff0c;被出质给…

【SGX系列教程】(三)Intel-SGX 官方示例分析(SampleCode)——SampleEnclave

文章目录 一. 引言二. README2.1 项目目的2.2 构建和执行示例代码的步骤2.3 配置参数解释2.4 配置文件分析2.5 启动令牌初始化 三. 重点代码分析3.1 App文件夹3.1.1 App/App.cpp3.1.2 App/Edger8rSyntax文件夹3.1.2.1 App/Edger8rSyntax/Arrays.cpp3.1.2.2 App/Edger8rSyntax/F…

一文全概括,建议收藏,那些你不可错过的IC设计书籍合集(可下载)

集成电路设计工程师的角色不仅是推动技术创新的中坚力量&#xff0c;更是实现产品从概念到现实的关键桥梁。随着对高性能、低功耗芯片的需求不断增长&#xff0c;IC设计工程师的专业技能和知识深度成为了衡量其职业价值的重要标准。无论是在数字逻辑设计、功能验证、可测试性设…

JMeter--定时执行的方法

原文网址&#xff1a;JMeter--定时执行的方法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍JMeter如何使用定时器定时执行测试任务。 Java技术星球&#xff1a;way2j.com 方法 第一步&#xff1a;新建定时器 右键测试任务> Add > Timer> Constant Timer 如下图所示…

qt中数据库和excel互导数据————附带详细步骤和代码

文章目录 0 背景1 准备QXlsx环境1.1 cmake安装使用1.2 qmake使用 2 把excel数据导出到mysql数据库3 把mysql数据库的数据写入到excel4 完整代码5 项目代码仓库 0 背景 因为需要批量导入和导出数据&#xff0c;所以需要用到excel。实现把数据库的数据导入到excel中&#xff0c;…

圆圈序号1~10复制粘贴直接用

1. 空心圆圈数字序号&#xff1a; ①、②、③、④、⑤、⑥、⑦、⑧、⑨、⑩ 2. 实心圆圈数字序号&#xff1a; ❶、❷、❸、❹、❺、❻、❼、❽、❾、❿ 3. 空心圆圈中文序号&#xff1a; ㊀、㊁、㊂、㊃、㊄、㊅、㊆、㊇、㊈、㊉

linux高级编程(线程)(1)

虚拟地址&#xff1a; 线程&#xff1a; 概念&#xff1a;线程是轻量级进程&#xff0c;一般是一个进程中的多个任务。 进程是系统中最小的资源分配单位。&#xff08;竞争计算机资源的最小单位&#xff09;&#xff08;进程能分配硬件资源&#xff0c;线程不行&#x…

解析QAnything启动命令过程

一.启动命令过程日志 启动命令bash ./run.sh -c local -i 0 -b hf -m Qwen-1_8B-Chat -t qwen-7b-chat。输入日志如下所示&#xff1a; rootMM-202203161213:/mnt/l/20230918_RAG方向/QAnything# bash ./run.sh -c local -i 0 -b hf -m Qwen-1_8B-Chat -t qwen-7b-chat From …

Leetcode Java学习记录——栈和队列 IDEA

文章目录 栈和队列stack Classqueue InterfaceDeque Interfaceadd 和 push Priority Queue -- Class题目 codestyleIDEA 操作快捷键选择代码生成类 栈和队列 stack Class google stack java 8/12 empty() peek() pop() push(E item) search(Object o) 最近相关性会用到栈 …

湘潭大学软件工程数据库总结

文章目录 前言试卷结构给学弟学妹的一些参考自己的一些总结 前言 自己可能很早很早之前就准备复习了&#xff0c;但是感觉还是没有学到要点&#xff0c;主要还是没啥紧迫的压力&#xff0c;我们是三月份开学&#xff0c;那时候实验室有朋友挺认真开始学习数据库了&#xff0c;…

理性决策的艺术:从购房到择偶的数学智慧;37% 规则,做出最佳决策的秘诀;用数学模型解决人生难题

在面对人生重大决策时&#xff0c;如购房或择偶&#xff0c;我们常常感到迷茫和困惑。然而&#xff0c;如果我们能够将这些看似复杂的问题简化为数学模型&#xff0c;我们就能以更加理性和系统的方式做出决策。 37%规则 1950年代&#xff0c;当时几位数学家开始研究这样一个问…

值得收藏!盘点那些适合普通人方便又好用的AIGC工具!(下)

【导读】接上一篇文章&#xff0c;盘点国内外适合普通人能够轻松上手的AIGC工具&#xff08;上&#xff09;。今天又为大家整理了一些好用又方便的AI设计工具、AI办公工具、AI编程工具、AI指令工具和AI检测工具&#xff0c;如果有没更新到的工具也欢迎大家评论区交流。 一 、A…

Kafka 入门指南

Kafka 入门指南 简介 Kafka 是一个由 Apache 软件基金会开发的开源流处理平台。它最初由 LinkedIn 开发&#xff0c;并在 2011 年作为开源项目发布。Kafka 是一个分布式、可扩展、高吞吐量的消息队列系统&#xff0c;广泛应用于实时数据流处理场景。 主要概念 1. 主题 (Top…