首页 新闻 会员 周边

有人解答一下,抖店开放平台的sign算法,为什么要求业务参数的json节点要重新排序再计算吗?

1
[待解决问题]

首先,抖店开放平台sign算法说明地址如下:https://op.jinritemai.com/docs/guide-docs/10/23

他们的API,http请求是以 application/json 的方式提交,业务参数放在了body体中,是一个json,比如 {"create_time_end":1656403855,"create_time_start":1655740799,"is_searchable":false,"page":0,"size":10}

这个json在传输的过程中是不会变化的,为什么还要求把这个json的节点(甚至是包括嵌套节点也要重新排序),重新按字母排序重组成一个新的json后,再来参与计算签名呢?
但是按我的理解,这个json在传输中是不会变化的,API接入者计算签名的时候,拿着这组字符串,直接计算签名,服务器端收到http请求后,先拿到body体里面的数据,直接计算签名,完全可以获得同一个结果,为什么非得排序再来计算呢?麻烦有经验的人解答下
因为我正在开发一个类似的开放平台,如果按抖店开放平台的这样子要求计算签名,开发者在接入的时候会麻烦不少,但是我又怕我考虑的太少(毕竟抖店是大厂),不进行排序会有一些我预料不到的问题,请大家解答,谢谢。

LoveCoder的主页 LoveCoder | 菜鸟二级 | 园豆:216
提问于:2023-11-01 22:28
< >
分享
所有回答(3)
0

...每个人配置json的顺序都不一样,那怎么保证计算的签名一样。肯定要有规则啊。

Supper_litt | 园豆:827 (小虾三级) | 2023-11-02 10:41

虽然每个人序列化的顺序不一样,但是你签名的时候 body体从客户端到服务器端是不会变化的,我拿着完整的raw body计算签名,和你客户端计算签名是一样的。也就是说,只要不对json进行反序列化和序列化,是不会改变json的内容的,这是我提问里面描述过的

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-02 11:51

@LoveCoder: 懂你的意思,我作为服务器,我是按照你的规则来玩,还是你按照我的规则来玩。你觉得呢。

支持(0) 反对(0) Supper_litt | 园豆:827 (小虾三级) | 2023-11-02 11:52

@Supper_litt: 现在我作为服务器,我就是要定规则,因为这条规则对接入者会造成不小的麻烦,所以我想知道抖店定这个规则的意义,以便我知道要不要学这条规则,我在提问,并不是想吐槽对方,谢谢

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-02 13:09

@LoveCoder: 有可能是因为这样打日志,到时间分析日志会方便许多?

支持(0) 反对(0) 人间春风意 | 园豆:2368 (老鸟四级) | 2023-11-02 14:05

@人间春风意: 怎么说?为什么这样子打日志会更方便呢?能详细说下吗?

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-02 15:02

@LoveCoder: 不是打日志,是后续出问题分析日志更快捷,且更便于开发人员一眼理解

支持(0) 反对(0) 人间春风意 | 园豆:2368 (老鸟四级) | 2023-11-03 08:48
0

存在即合理,肯定有什么问题导致的这样处理

Harry宗 | 园豆:216 (菜鸟二级) | 2023-11-02 17:01

所以,肯定是什么问题导致的?这是我想知道的,以便我在设计的时候要不要这么做,别告诉我无脑抄就可以了,如果你是这么想的,那可能我们观点不太一致

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-02 17:11
1

好吧,看着大家的回复都每说出真正的原因比较心累。

首先你要明白一个事实,对于 {"age":"33","city":"北京","gender":"男","name":"张三"} 和 {"name":"张三","age":"33","gender":"男","city":"北京"} 这两个JSON MD5出来的值是不一样(辛苦自己去验证).... 因此即使意义相同的JSON只是因为在组合时顺序不一致时MD5的结果就不一样,那么问题就来了,如果你是一个提供接口的服务端开发者,你要怎么办??? 难道你要遍历所有的组合的可能吗?然后硬暴力来适配处理????假使你真的可以,如果下次接口添加或者修改参数呢?结果将是灾难性的。。。
那要解决这个问题的办法当然也就应运而生,就是作为接口开发的服务端提供统一的编码规则,也就是根据JSON的Key来按照字母表排序,这样子拍出来的JSON那么他的MD5结果就是固定的...因此也就避免了你说的这个问题。
另外在回答下关于你说的你序列化出来的JSON从你侧发起到抖音服务端接收到你的JSON,你的理解是传输过程中JSON的内容是不会发生变化的(你的原文“你签名的时候 body体从客户端到服务器端是不会变化的”),这个说法只适用于通常情况,不适用于所有情况,换个说法就是,HTTP协议本身不会对JSON数据进行任何修改或处理,但是你架不住数据传输过程中的比如负载均衡、代理等等乱七八糟的中间件的好吧,或者说作为服务提供者原则上是不会信任任何不按照规范进行数据传输的数据的...
因此从最小化成本角度来考虑,最简单有效的办法就是统一一个规则,接入方按照规则生成sign,服务端接收到数据后对JSON进行排序并sign,进行比较是最经济有效的解决办法,也是目前业界通用的解决办法。

西越泽 | 园豆:10775 (专家六级) | 2023-11-05 21:33

所以我是接口提供者,我为什么要遍历所有组合呢?我直接把你从客户端传来的http报文里面的body直接拿到,进行签名验算,为什么你会说需要遍历所有可能性呢?还有,数据传输中的负载均衡,代理这些人最基本的不修改报文是最基本的吧?难道中间的这些人还有会修改报文的body,故意打乱顺序去吗?

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-05 21:41

@LoveCoder: 上面说的很清楚了,不行你可以自己试试。
你所谓的、理解的或者说认识的只是通常情况,不适用于所有情况... 要应对复杂环境时一定是采用统一规则的做法的...
说的在难听点,你能想到的通常情况相信抖音服务部门的开发者他们也同样是知道的,那为啥他们还要来规范这件事情呢?
其次,你接口看到的是JSON进行数据传输的,但是你要知道在他们接收到你数据后在服务内部传输过程你认为他们也原本用你的JSON吗?有没有考虑过人家用的是私有RPC协议呢?到具体处理数据服务的时候RPC反序列化后的数据顺序还是你传入的数据吗?

支持(1) 反对(0) 西越泽 | 园豆:10775 (专家六级) | 2023-11-05 21:58

@西越泽: 嗯,也就是说,主要原因还是可能客户端到真正的服务器接收端中,可能会经过多层的处理中心,这些不同步骤有可能用的不是http协议,可能会对数据json进行数据的序列化和反序列化操作。
综合来说就是一句话,数据从客户端到达真正的处理者手上,可能会需要经过序列化和反序列化,已经不是原始的报文了?是这样子理解吧?
但是,按我的理解,api首先到达的应该是网关中心,这一步一定http协议的,网关中心一定是能拿到原始报文的。网关中心先验签,验证通过的才放行,后续再怎么流转,签名已经不存在了。
我对接过很多开放平台,以json提交业务参数的还有支付宝开放平台,他们的业务参数放在 biz_content 这个参数中,但是这个参数和其他参数,比如sign,timestamp参数等合在一起,用表单的方式提交,他们是没有要求这个biz_content的节点进行排序的

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-05 22:07

@LoveCoder: 感觉应该是 最小化成本角度来考虑 这个原因,固定的规则可以避免很多问题,便于维护,{"age":"33","city":"北京","gender":"男","name":"张三"} = 329d23a57b074d9da45a47c2b44360d5 {"name":"张三","age":"33","gender":"男","city":"北京"} = 2a9f0be64e623f879c5064e664d5a704,同样的参数 MD5值是不同的,如果你不需要保证MD5或者某个签名在意义相同JSON的情况下保持不变的话,好像就没必要限制的太死,按需求开发呗

支持(0) 反对(0) RolyPoly_Toy | 园豆:217 (菜鸟二级) | 2023-11-07 09:54

@IT小苍: 是的,我当初也考虑过这个问题,但是仔细一推敲,又不是。为什么呢?因为它的sign还需要时间戳参与计算,也就是说,除非某个人在某个固定时间戳内,发起了2次请求,这2次请求的json符合你刚刚举例的这个情况,它们的sign才会一样,但是这种场景毫无意义,所有我觉得这个猜想又不太对。
假设如果计算签名只是单纯的对body体计算,不需要其他值参与计算的话,那这个猜想的确是非常有可能的,因为他们可能希望将符合这个情况的json做为同一种请求来统计某些东西,但是有时间戳、用户身份标志等变量来参与计算,根本就没办法确定这是同一个请求了

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-07 10:00

@LoveCoder: 如果这个排除的话,按照字典排序的优势就是 ASCII码值从左到到排序,以便使读者更容易找到想要的文字或数字,便于索引,其他用处就想不到了,毕竟日常开发很难达到抖音的量级,可能是为了方便抖音内部其他模块的数据采集需求

支持(0) 反对(0) RolyPoly_Toy | 园豆:217 (菜鸟二级) | 2023-11-07 10:15

@LoveCoder: 不是故意打乱顺序, 现在开发的后端接口中, 开发人员拿到的数据,一般不是你的json, 而是一个类的实体, 就好比学生信息, 你给我传 的是 {"name":"学生", "sex":"男"}, 你觉得是这个顺序,没问题, 但是接口接收那边拿到的是一个学生类, 里面有两个属性, 一个name , 一个sex, 他不知道你传的顺序的, 所以大家做一个约定, 对所有的字段按一定的规则排序,这样大家做校验就统一了

支持(0) 反对(0) 百鸟朝凤 | 园豆:260 (菜鸟二级) | 2023-11-07 11:18

@百鸟朝凤: 这个其实也不太可能,正常这种API都有统一的网关进入,数据正常是先进入到网关,网关这一步就会验签,正常都是不会让每个方法自己验签的,你说的这种情况,如果是每个方法都自己验签,而且就算接口那边拿到了是实体类,那应该也是可以拿到http的原始报文的吧。

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-07 11:23

@LoveCoder: 我这是举个例子,网关拿到数据, 一般也不会直接用你的原始报文, 自己去解析是json么, 不会的,都是会进行序列化的, 序列化之后才会进行验签, 这个时候, 你原始报文的顺序就没用了. 如果是java 程序员的话, 我估计大概率会用map去序列化, 然后循环序列化对象,排序,进行验签.

支持(0) 反对(1) 百鸟朝凤 | 园豆:260 (菜鸟二级) | 2023-11-07 11:28

@百鸟朝凤: 为什么网关拿到以后要序列化再来验签?签名压根不关心参数的每个字段的内容,只需要关心整个字符串的内容,所以为什么一般要先反序列化,再序列化拿字符串再来验签呢?我认为作为程序员,每多写一行代码都要思考它的必要性吧,没必要的代码就没有写上去的必要。

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-07 11:37

@LoveCoder: 嗯...你觉得是操作字符串,自己拆分拼接方便呢, 还是序列化成对象, 操作对象方便呢..

支持(0) 反对(0) 百鸟朝凤 | 园豆:260 (菜鸟二级) | 2023-11-07 11:39

@百鸟朝凤: 对于验签的这个过程来说,当然是操作字符串容易。你要考虑到接入者,因为这是开放平台,是需要提供给很多开发者接入,开发者用的语言也不一样,拆json排序,重组json这个还是有点麻烦的。

支持(0) 反对(0) LoveCoder | 园豆:216 (菜鸟二级) | 2023-11-07 11:44

@LoveCoder: 不不...无论用什么语言,他都可以先创建对象, 填入数据之后, 再用对象自带的排序方法进行排序, 然后反序列化成json就可以了. java 有 map, C# 有 字典, 别的语言没用过, 但是也会有这些方法..

支持(0) 反对(0) 百鸟朝凤 | 园豆:260 (菜鸟二级) | 2023-11-07 11:48
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册