请求重放、重放攻击

重放攻击(英语:replay attack,或称为回放攻击)是一种恶意或欺诈的重复或延迟有效数据的网络攻击形式。 这可以由发起者或由拦截数据并重新传输数据的对手来执行,这可能是通过IP数据包替换进行的欺骗攻击的一部分。 这是“中间人攻击”的一个较低级别版本。

这种攻击的另一种描述是: “从不同上下文将消息重播到安全协议的预期(或原始和预期)上下文,从而欺骗其他参与者,致使他们误以为已经成功完成了协议运行。”

有一天,我去洗脚的时候对着店员说:给我安排一个 168 价位的,要小伙子啊,按着比较带劲儿,我的卡号是 88888888。

然后我在前台签上了自己的名字,店员就安排了一个精壮的小伙子给我按摩。

没想到我们的对话被其他人听到了,于是他也给店员说:给我安排一个 168 价位的,要小伙子啊,按着比较带劲儿,我的卡号是 88888888。

还模仿了我的签名,在前台签字。

把之前的、正常的请求再次发送,这就是重放攻击。

有的朋友就会说了:我的接口是加签的,应该没问题吧?

你加签咋了?

我没有动你的报文,所以你也可以正常验签呀。

我不仅抄你报文里面的正常字段,报文里面的签名我也抄全乎了。

所以,接收方接到报文之后能正常验签。

没有任何毛病。

有的朋友还会说了:我的接口是有加密的,应该没问题吧?

看来还是不懂重放攻击的基本原理。

你加密咋了?

反正我截取到了你的报文,虽然你报文加密了,我看起来是一段乱码,但是我也不需要知道你报文的具体内容呀,直接重发就完事了。

还是前面的例子。

假设我去洗脚的时候对着店员说:天王盖地虎。

被旁边的人听到了,他根本就不知道“天王盖地虎”是啥。

但是他看到了我说了这句话之后,就被安排了一个 168 元的技术服务。

于是他也对店员说:天王盖地虎。

也能被安排。

所以,别人根本就不需要知道你报文的具体含义

只要我再次发给你,你进行解密操作,发现能解密。

能解密说明暗号对上了。

所以,虽然报文是加密、加签传输的,对于防止请求重放,并没有什么卵用。

https://blog.csdn.net/qq_27243343/article/details/116984239

加密的目的:为了保证传输信息的隐私性,不被别人看到传输的具体内容,只能让接收方看到正确的信息。

加签的目的:消息接收方验证信息是否是合法的发送方发送的,确认信息是否被其他人篡改过。

啥是中间人攻击呢?

我去洗脚的时候对着店员说:给我安排一个 168 价位的,要小伙子啊,按着比较带劲儿,我的卡号是 88888888。

对话被偷听到了,中间人对店员说:给我安排一个 1999 价位的,要小姑凉啊,按摩手法好一点的,我的卡号是 88888888。

篡改报文,这是中间人攻击。

解决方案

加时间戳

首先,常见的解决方案就是在请求报文里面加上时间戳,并参与加签。

当接收方收到报文,经过验签之后。

首先第一个事儿就是拿着请求中的时间戳字段和本地时间做个对比。

如果时间误差在指定时间,比如 60 秒内,那么认为这个请求是合理的,程序可以继续处理。

为什么要有一个时间容错范围,能理解吧?

因为报文的传输、解密、验签是需要时间,不能假设我这一秒发出去,下一秒服务端就收到了。

所以,得有时间容错范围。

但是这个容错范围又带来了另外一个问题。

不能完全避免重放攻击。

至少时间容错范围内,比如 60 秒,重发过来的请求,服务端认为是有效的。

那么怎么办呢?

加随机串

换个思路,我们在请求报文里面加个随机串,然后让它参与加签。

接受方收到报文,验签之后,把随机串拿出来,来判断一下这个随机串是否已经处理过了。比如判断一下是否存在于 Redis 里面。

当请求再次重放过来的时候,一看:嚯,好家伙,这个随机串已经被用过了呀,不处理了。

在这个情况下,随机串就得保证唯一性了,还得历史全局唯一。

因为你指不定哪天就收到一个几天前的被重放过来的请求。

确实是解决了请求重放的问题,但是弊端也很明显:历史全局唯一。

我还得存储下来,而且存储的数据量还会越来越大,是不是有点麻烦了?

确实麻烦了。

这个思想就和用全局唯一流水号去保证接口幂等性很像了。

所以,我第一次遇到这个面试题的时候,我朝着接口幂等的角度去回答了,也不能说回答的不对。

只能说回答的不是面试官想要的标准答案。

那么什么是面试官想要听到的回答呢?

时间戳+随机串

时间戳的问题是有一定的时间容错窗口,这个时间窗口内的重放攻击是防不住的。

随机串的问题是要保证历史全局唯一,保存随机串成了一个麻烦的事情。

那么当我们把这两个方案揉在一起的时候,神奇的事情就发生了:

我只需要保证时间窗口内的生成的随机串不重复就行。

而且假设时间窗口为 60 秒,我们用 Redis 来记录出现过的随机串,那么这个串在后台的超时时间设置为 60 秒就行。

一般来说这个时间窗口都不会太长了,我对接过这么多各种各样的渠道,见过最长的也就 5 分钟。

保证 5 分钟内生成的两个随机串不重复,这个需求比保证实现一个历史全局唯一的流水号容易实现多了吧?

另外,最关键的一句话一定要说:时间戳和随机串得参与到加签逻辑中去。

这个很好理解吧?

接受方看报文是否被篡改,看的就是签名是否能匹配上。

而签名的结果是和参与签名的字段的值有直接关系的。

要是你时间戳和随机串不参与加签,那么任意修改时间戳或者随机串,都不会引起签名的变化,那不白忙活一场吗?

中间人咔一下拦截到请求,发现有时间戳和随机串,正准备放弃的时候,想着死马当做活马医,把随机串一改,又扔给接收方了。

结果收到正确的响应了。

我要是这个中间人,我都会笑出来声来:写这个代码的程序员也太可爱了吧?

https://blog.csdn.net/qq_27243343/article/details/116984239

微信支付

其实说到时间戳加随机串的时候,我就想起了微信支付。

https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_3_9.shtml

0

阿里API网关

看完微信支付,再看看阿里的 API 网关是怎么防止重放攻击的。

https://help.aliyun.com/knowledge_detail/50041.html

0

阿里的 API 网关,就是在 HEADER 里面加了两个参数:X-Ca-Timestamp、X-Ca-Nonce。

这个解决方案就是我们前面说的时间戳加随机串。

https://blog.csdn.net/qq_27243343/article/details/116984239

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注