小结一下,HTTP-规范中的那些容易掉进去的坑,直面春招

2.冲突的协议

我们首先看看 URI 中的保留字,这些保留字不参与编码。保留字符一共有两大类:

  • gen-delims:: / ? # [ ] @
  • sub-delims:! $ & ' ( ) * + , ; =

URI 的编码规则也很简单,先把非限定范围的字符转为 16 进制,然后前面加百分号。

空格这种不安全字符转为十六进制就是 0x20,前面再加上百分号 % 就是 %20

所以这时候再看 encodeURIComponent 和 encodeURI 的编码结果,就是完全正确的。

既然空格转为%20 是正确的,那转为 + 是怎么回事?这时候我们就要了解一下 HTML form 表单的历史。

早期的网页没有 AJAX 的时候,提交数据都是通过 HTML 的 form 表单。form 表单的提交方法可以用 GET 也可以用 POST,大家可以在 MDN form 词条上测试:

经过测试我们可以看出表单提交的内容中,空格都是转为加号的,这种编码类型就是 application/x-www-form-urlencoded,在 WHATWG 规范里是这样定义的:

到这里基本上就破案了,URLSearchParams 做 encode 的时候,就按这个规范来的。我找到了 URLSearchParams 的 Polyfill 代码,里面就做了 %20 到 + 的映射:

replace = {
    '!': '%21',
    "'": '%27',
    '(': '%28',
    ')': '%29',
    '~': '%7E',
    '%20': '+', // <= 就是这个
    '%00': '\x00'
}

规范里对这个编码类型还有解释说明:

The application/x-www-form-urlencoded format is in many ways an aberrant monstrosity, the result of many years of implementation accidents and compromises leading to a set of requirements necessary for interoperability, but in no way representing good design practices. In particular, readers are cautioned to pay close attention to the twisted details involving repeated (and in some cases nested) conversions between character encodings and byte sequences. Unfortunately the format is in widespread use due to the prevalence of HTML forms.

这种编码方式就不是个好的设计,不幸的是随着 HTML form 表单的普及,这种格式已经推广开了

其实上面一大段句话就是一个意思:这玩意儿设计的就是 💩,但积重难返,大家还是忍一下吧

3.一句话总结

  • URI 规范里,空格 encode 为 %20, application/x-www-form-urlencoded 格式里,空格 encode 为 +

  • 实际业务开发时,最好使用业内成熟的 HTTP 请求库封装请求,这些杂活儿累活儿框架都干了;

  • 如果非要使用原生 AJAX 提交 application/x-www-form-urlencoded 格式的数据,不要手动拼接参数,要用 URLSearchParams 处理数据,这样可以避免各种恶心的编码冲突。

三.X-Forwarded-For 拿到的就是真实 IP 吗?

1.故事

在这个小节开始前,我先讲一个开发中的小故事,可以加深一下大家对这个字段的理解。

前段时间要做一个和风控相关的需求,需要拿到用户的 IP,开发后灰度了一小部分用户,测试发现后台日志里灰度的用户 IP 全是异常的,哪有这么巧的事情。随后测试发过来几个异常 IP:

10.148.2.122
10.135.2.38
10.149.12.33
...

一看 IP 特征我就明白了,这几个 IP 都是 10 开头的,属于 A 类 IP 的私有 IP 范围(10.0.0.0-10.255.255.255),后端拿到的肯定是代理服务器的 IP,而不是用户的真实 IP。

2.原理

现在有些规模的网站基本都不是单点 Server 了,为了应对更高的流量和更灵活的架构,应用服务一般都是隐藏在代理服务器之后的,比如说 Nginx。

加入接入层后,我们就能比较容易的实现多台服务器的负载均衡和服务升级,当然还有其他的好处,比如说更好的内容缓存和安全防护,不过这些不是本文的重点就不展开了。

网站加入代理服务器后,除了上面的几个优点,同时引入了一些新的问题。比如说之前的单点 Server,服务器是可以直接拿到用户的 IP 的,加入代理层后,如上图所示,(应用)原始服务器拿到的是代理服务器的 IP,我前面讲的故事的问题就出在这里。

Web 开发这么成熟的领域,肯定是有现成的解决办法的,那就是 X-Forwarded-For 请求头。

X-Forwarded-For 是一个事实标准,虽然没有写入 HTTP RFC 规范里,从普及程度上看其实可以算 HTTP 规范了。

这个标准是这样定义的,每次代理服务器转发请求到下一个服务器时,要把代理服务器的 IP 写入 X-Forwarded-For 中,这样在最末端的应用服务收到请求时,就会得到一个 IP 列表:

X-Forwarded-For: client, proxy1, proxy2

因为 IP 是一个一个依次 push 进去的,那么第一个 IP 就是用户的真实 IP,取来用就好了。

但是,事实有这么简单吗?

3.攻击

从安全的角度上考虑,整个系统最不安全的就是人,用户端都是最好攻破最好伪造的。有些用户就开始钻协议的漏洞:X-Forwarded-For 是代理服务器添加的,如果我一开始请求的 Header 头里就加了 X-Forwarded-For ,不就骗过服务器了吗?

1. 首先从客户端发出请求,带有 X-Forwarded-For 请求头,里面写一个伪造的 IP:

X-Forwarded-For: fakeIP

2. 服务端第一层代理服务收到请求,发现已经有 X-Forwarded-For,误把这个请求当成代理服务器,于是向这个字段追加了客户端的真实 IP:

X-Forwarded-For: fakeIP, client

3. 经过几层代理后,最终的服务器拿到的 Header 是这样的:

X-Forwarded-For: fakeIP, client, proxy1, proxy2

要是按照取 X-Forwarded-For 第一个 IP 的思路,你就着了攻击者的道了,你拿到的是 fakeIP,而不是 client IP。

4.破招

服务端如何破招?上面三个步骤:

  • 第一步是客户端造假,服务器无法介入
  • 第二步是代理服务器,可控,可防范
  • 第三步是应用服务器,可控,可防范

第二步的破解我拿 Nginx 服务器举例。

我们在最外层的 Nginx 上,对 X-Forwarded-For 的配置如下:

proxy_set_header X-Forwarded-For $remote_addr;

什么意思呢?就是最外层代理服务器不信任客户端的 X-Forwarded-For 输入,直接覆盖,而不是追加

非最外层的 Nginx 服务器,我们配置:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

$proxy_add_x_forwarded_for 就是追加 IP 的意思。通过这招,就可以破解用户端的伪造办法。

第三步的破解思路也很容易,正常思路我们是取X-Forwarded-For 最左侧的 IP,这次我们反其道而行之,从右边数,减去代理服务器的数目,那么剩下的 IP 里,最右边的就是真实 IP。

X-Forwarded-For: fakeIP, client, proxy1, proxy2

比如说我们已知代理服务有两层,从右向左数,把 proxy1 和 proxy2 去掉,剩下的 IP 列表最右边的就是真实 IP。

相关思路和代码实现可参考 Egg.js 前置代理模式

5.一句话总结总结

通过 X-Forwarded-For 获取用户真实 IP 时,最好不要取第一个 IP,以防止用户伪造 IP。

四.略显混乱的分隔符

最后

由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。

image

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。
有需要的朋友可以点击这里免费获取

image

点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。
有需要的朋友可以点击这里免费获取

[外链图片转存中…(img-wK8LDIjs-1628440784743)]

image

2023年3月11日,美团春季招聘笔试共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目三:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值