fastjson 1.2 版本之前的bug, 反序列化时自动排序,导致签名不过

大家好,我是烤鸭:
今天分享一个问题,使用fastjson 导致签名不过。

1.  问题复现:


fastjson 1.2.4
获取返回值:

{"data":[{"id":"120190422110857284042111114","bankAccountType":"DEBIT","isMainCard":"0","bindId":"120190422110857284042111114","bankCardPhone":"15010311111","realName":null,"partBankAccountNo":"1199","bindChannel":"11111_PROTOCOL","masterAccountNo":null,"branchBankName":"建设银行","bankCode":"CCB"}],"sign":"nIBnR5YpoiYg4CwYIs5l1K2ne30X7A55YtjJH9teHYcZkRcPcI/ECg/TzKiMCFtKssOk1F8hXjC3Of2NhgYcduZAw4VjBb4HMuz9qRgSlZht0CXsMh8RVyysbJcKe8zhd4mansWzlxnIK2Kh3YnKf9Hzd/cHlcczr6UnDeifbZk="}

获取返回值中的数组:
 

[{"bankCode":"CCB","bankAccountType":"DEBIT","branchBankName":"建设银行","partBankAccountNo":"1199","id":"120190422110857284042111114","bindChannel":"11111_PROTOCOL","isMainCard":"0","bindId":"120190422110857284042111114","bankCardPhone":"15010311111"}]

fastjson 1.1.32
获取返回值:

{"data":[{"id":"120190422110857284042111114","bankAccountType":"DEBIT","isMainCard":"0","bindId":"120190422110857284042111114","bankCardPhone":"15010311111","realName":null,"partBankAccountNo":"1199","bindChannel":"11111_PROTOCOL","masterAccountNo":null,"branchBankName":"建设银行","bankCode":"CCB"}],"sign":"nIBnR5YpoiYg4CwYIs5l1K2ne30X7A55YtjJH9teHYcZkRcPcI/ECg/TzKiMCFtKssOk1F8hXjC3Of2NhgYcduZAw4VjBb4HMuz9qRgSlZht0CXsMh8RVyysbJcKe8zhd4mansWzlxnIK2Kh3YnKf9Hzd/cHlcczr6UnDeifbZk="}

获取返回值中的数组:

[{"bankAccountType":"DEBIT","bankCardPhone":"15010311111","bankCode":"CCB","bindChannel":"11111_PROTOCOL","bindId":"120190422110857284042111114","branchBankName":"建设银行","id":"120190422110857284042111114","isMainCard":"0","partBankAccountNo":"1199"}]

由于引入第三方的jar包,在返回值验签的时候报错。第三方jar中使用的fastjson 版本是 1.1.32,而我们项目中使用的是 1.2.4。
可以看到取出数组数据之后的不同点。一个是按字母升序排列的,一个是按自然排序(放入的顺序)。真的是坑....

2.  源码分析:

fastjson 1.2.4 

com.alibaba.fastjson.serializer.ListSerializer
代码更简洁了,去掉了对array的排序功能

public final void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features)throws IOException {boolean writeClassName = serializer.isEnabled(SerializerFeature.WriteClassName);SerializeWriter out = serializer.getWriter();Type elementType = null;if (writeClassName) {if (fieldType instanceof ParameterizedType) {ParameterizedType param = (ParameterizedType) fieldType;elementType = param.getActualTypeArguments()[0];}}if (object == null) {if (out.isEnabled(SerializerFeature.WriteNullListAsEmpty)) {out.write("[]");} else {out.writeNull();}return;}List<?> list = (List<?>) object;if (list.size() == 0) {out.append("[]");return;}SerialContext context = serializer.getContext();serializer.setContext(context, object, fieldName, 0);ObjectSerializer itemSerializer = null;try {if (out.isEnabled(SerializerFeature.PrettyFormat)) {out.append('[');serializer.incrementIndent();int i = 0;for (Object item : list) {if (i != 0) {out.append(',');}serializer.println();if (item != null) {if (serializer.containsReference(item)) {serializer.writeReference(item);} else {itemSerializer = serializer.getObjectWriter(item.getClass());SerialContext itemContext = new SerialContext(context, object, fieldName, 0, 0);serializer.setContext(itemContext);itemSerializer.write(serializer, item, i, elementType, 0);}} else {serializer.getWriter().writeNull();}i++;}serializer.decrementIdent();serializer.println();out.append(']');return;}out.append('[');int i = 0;for (Object item : list) {if (i != 0) {out.append(',');}if (item == null) {out.append("null");} else {Class<?> clazz = item.getClass();if (clazz == Integer.class) {out.writeInt(((Integer) item).intValue());} else if (clazz == Long.class) {long val = ((Long) item).longValue();if (writeClassName) {out.writeLongAndChar(val, 'L');} else {out.writeLong(val);}} else {SerialContext itemContext = new SerialContext(context, object, fieldName, 0, 0);serializer.setContext(itemContext);if (serializer.containsReference(item)) {serializer.writeReference(item);} else {itemSerializer = serializer.getObjectWriter(item.getClass());itemSerializer.write(serializer, item, i, elementType, 0);}}}i++;}out.append(']');} finally {serializer.setContext(context);}}

fastjson 1.1.32
StringDeserializer

public static <T> T deserialze(DefaultJSONParser parser) {final JSONLexer lexer = parser.getLexer();if (lexer.token() == JSONToken.LITERAL_STRING) {String val = lexer.stringVal();lexer.nextToken(JSONToken.COMMA);return (T) val;}if (lexer.token() == JSONToken.LITERAL_INT) {String val = lexer.numberString();lexer.nextToken(JSONToken.COMMA);return (T) val;}Object value = parser.parse();if (value == null) {return null;}return (T) value.toString();
}public Object parse(Object fieldName) {final JSONLexer lexer = getLexer();switch (lexer.token()) {case SET:lexer.nextToken();HashSet<Object> set = new HashSet<Object>();parseArray(set, fieldName);return set;case TREE_SET:lexer.nextToken();TreeSet<Object> treeSet = new TreeSet<Object>();parseArray(treeSet, fieldName);return treeSet;case LBRACKET:JSONArray array = new JSONArray();parseArray(array, fieldName);return array;case LBRACE:JSONObject object = new JSONObject();return parseObject(object, fieldName);case LITERAL_INT:Number intValue = lexer.integerValue();lexer.nextToken();return intValue;case LITERAL_FLOAT:Object value = lexer.decimalValue(isEnabled(Feature.UseBigDecimal));lexer.nextToken();return value;case LITERAL_STRING:String stringLiteral = lexer.stringVal();lexer.nextToken(JSONToken.COMMA);if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);try {if (iso8601Lexer.scanISO8601DateIfMatch()) {return iso8601Lexer.getCalendar().getTime();}} finally {iso8601Lexer.close();}}return stringLiteral;case NULL:lexer.nextToken();return null;case TRUE:lexer.nextToken();return Boolean.TRUE;case FALSE:lexer.nextToken();return Boolean.FALSE;case NEW:lexer.nextToken(JSONToken.IDENTIFIER);if (lexer.token() != JSONToken.IDENTIFIER) {throw new JSONException("syntax error");}lexer.nextToken(JSONToken.LPAREN);accept(JSONToken.LPAREN);long time = ((Number) lexer.integerValue()).longValue();accept(JSONToken.LITERAL_INT);accept(JSONToken.RPAREN);return new Date(time);case EOF:if (lexer.isBlankInput()) {return null;}throw new JSONException("unterminated json string, pos " + lexer.getBufferPosition());case ERROR:default:throw new JSONException("syntax error, pos " + lexer.getBufferPosition());}
}

重点在于:

case LBRACKET:JSONArray array = new JSONArray();parseArray(array, fieldName);return array;

DefaultJSONParser:

public final void parseArray(final Collection array, Object fieldName) {final JSONLexer lexer = getLexer();if (lexer.token() == JSONToken.SET || lexer.token() == JSONToken.TREE_SET) {lexer.nextToken();}if (lexer.token() != JSONToken.LBRACKET) {throw new JSONException("syntax error, expect [, actual " + JSONToken.name(lexer.token()) + ", pos "+ lexer.pos());}lexer.nextToken(JSONToken.LITERAL_STRING);ParseContext context = this.getContext();this.setContext(array, fieldName);try {for (int i = 0;; ++i) {if (isEnabled(Feature.AllowArbitraryCommas)) {while (lexer.token() == JSONToken.COMMA) {lexer.nextToken();continue;}}Object value;switch (lexer.token()) {case LITERAL_INT:value = lexer.integerValue();lexer.nextToken(JSONToken.COMMA);break;case LITERAL_FLOAT:if (lexer.isEnabled(Feature.UseBigDecimal)) {value = lexer.decimalValue(true);} else {value = lexer.decimalValue(false);}lexer.nextToken(JSONToken.COMMA);break;case LITERAL_STRING:String stringLiteral = lexer.stringVal();lexer.nextToken(JSONToken.COMMA);if (lexer.isEnabled(Feature.AllowISO8601DateFormat)) {JSONScanner iso8601Lexer = new JSONScanner(stringLiteral);if (iso8601Lexer.scanISO8601DateIfMatch()) {value = iso8601Lexer.getCalendar().getTime();} else {value = stringLiteral;}iso8601Lexer.close();} else {value = stringLiteral;}break;case TRUE:value = Boolean.TRUE;lexer.nextToken(JSONToken.COMMA);break;case FALSE:value = Boolean.FALSE;lexer.nextToken(JSONToken.COMMA);break;case LBRACE:JSONObject object = new JSONObject();value = parseObject(object, i);break;case LBRACKET:Collection items = new JSONArray();parseArray(items, i);value = items;break;case NULL:value = null;lexer.nextToken(JSONToken.LITERAL_STRING);break;case RBRACKET:lexer.nextToken(JSONToken.COMMA);return;default:value = parse();break;}array.add(value);checkListResolve(array);if (lexer.token() == JSONToken.COMMA) {lexer.nextToken(JSONToken.LITERAL_STRING);continue;}}} finally {this.setContext(context);}
}

com.alibaba.fastjson.serializer.SerializeWriter

writeStringWithDoubleQuote()   重排序

 System.arraycopy(buf, lastSpecialIndex + 1, buf, lastSpecialIndex + 2, end - lastSpecialIndex - 1);buf[lastSpecialIndex] = '\\';buf[++lastSpecialIndex] = replaceChars[(int) lastSpecial];

小结:


由于 fastjson 版本 1.1.32 在反序列化的时候,自动排序了。而 1.2.4 以后的版本没有自动排序,如果加解密的json 版本不一样,就会导致加解密出错。
去阿里的仓库找fastjson,发现已经没有 1.2.4之前的版本了,说明之前的版本确实有问题。

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

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

相关文章

[css] 你知道CSS中的字母“C“代表什么吗?

[css] 你知道CSS中的字母"C"代表什么吗&#xff1f; CSS(Cascading Style Sheets)。"C" 即为 Cascading 层叠的意思&#xff0c;我们编写 CSS 的时候&#xff0c;写在后面的样式会覆盖前面的样式即层叠。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流…

[Network Architecture]DPN(Dual Path Network)算法详解(转)

https://blog.csdn.net/u014380165/article/details/75676216 论文&#xff1a;Dual Path Networks 论文链接&#xff1a;https://arxiv.org/abs/1707.01629 代码&#xff1a;https://github.com/cypw/DPNs MXNet框架下可训练模型的DPN代码&#xff1a;https://github.com/m…

[css] 怎么自定义鼠标指针的图案?

[css] 怎么自定义鼠标指针的图案&#xff1f; cursor: url() ,auto url是自定义光标图案的绝对路径&#xff0c;auto是默认光标&#xff0c;当我们自定义的光标不起作用时&#xff0c;就用默认光标代替。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容…

javax.script.ScriptException: ReferenceError: xxx is not defined in eval

大家好&#xff0c;我是烤鸭&#xff1a; 今天使用 javax.script.ScriptEngine 遇到一个奇怪的问题&#xff0c;无法识别js方法。 1. 报错内容&#xff1a; javax.script.ScriptException: ReferenceError: "a" is not defined in <eval> at line number…

Python的特殊成员

Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用’from module import *’导入 __xxx__ 系统定义名字 __xxx 类中的私有变量名 核心风格&#xff1a;避免用下划线作为变量名的开始。 现在我们来总结下所有的系统定义属性和方法&#xff0c; 先来看下保留属性&#…

[css] Reset CSS和Normalize CSS的区别是什么?

[css] Reset CSS和Normalize CSS的区别是什么&#xff1f; Reset&#xff1a;将所有浏览器的默认样式都统一化&#xff0c;注重的是跨浏览器统一样式&#xff0c;用户还要自行添加一些默认样式。 Normalize&#xff1a;会根据各个浏览器的不同保留有用的浏览器特色样式&#x…

java 实现 常见排序算法(四)基数排序

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下基础排序算法之基数排序。 1. 基数排序&#xff1a; 原理&#xff1a;基数排序&#xff08;radix sort&#xff09;属于“分配式排序”&#xff08;distribution sort&#xff09;&#xff0c;又称“桶子法”&#…

vyos User Guide

vyos User Guide 来源 https://wiki.vyos.net/wiki/User_Guide The VyOS User Guide is focused on providing a general overview of the installation, configuration, and operation of the VyOS network operating system. Introduction VyOS is a Linux-based network ope…

[css] 为什么要使用css sprites?

[css] 为什么要使用css sprites&#xff1f; 减少HTTP请求增加图片显示速度个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Java 面试题(3)—— JVM

JVM的内存结构。 JVM主要结构&#xff1a;堆内存、栈、方法区&#xff0c;程序计数器&#xff0c;永久代&#xff09;&#xff08;jdk 8采用元空间替代&#xff09;。 堆内存又分成年轻代和年老代。 年轻代由三部分组成&#xff0c;Eden、From Survivor 和 To Survivor&#xf…

[css] 标签、class和id选择器三者的区别是什么?分别在什么时候用?

[css] 标签、class和id选择器三者的区别是什么&#xff1f;分别在什么时候用&#xff1f; 标签选择器&#xff1a;tag{} 选取对应的标签例如 a span div class选择器&#xff1a;.class-name{} 选取对应class-name的元素 id选择器&#xff1a;#id-name{} 选取对应id的元素 其中…

web前端开发怎么样学习?看这份web前端学习路线

前端开发是创建Web页面或app等前端界面呈现给用户的过程。前端开发通过HTML&#xff0c;CSS及JavaScript以及衍生出来的各种技术、框架、解决方案&#xff0c;来实现互联网产品的用户界面交互。它从网页制作演变而来&#xff0c;名称上有很明显的时代特征。在互联网的演化进程中…

今天分享一下做支付宝小程序遇到的坑。ISV权限不足,建议在开发者中心检查对应功能是否已经添加。验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下做支付宝小程序遇到的坑。pom版本 <!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-j…

[css] 举例说明时间、频率、角度、弧度、百分度的单位分别是哪些?

[css] 举例说明时间、频率、角度、弧度、百分度的单位分别是哪些&#xff1f; 时间: s, ms频率: Hz角度: deg弧度: rad百分度: grad个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起…

[洛谷P4918]信仰收集

题目背景 随着各种势力的迁入,守矢神社丧失了不少信仰现在,为了挽回香火日益惨淡的神社,八坂神奈子派遣神社的风祝早苗去人类村落收集信仰 题目描述 你可以将村落看成一个m个点的有向无环图(编号从1−m),其中在某些点上有n簇待收集的信仰(每一簇都有一定的数量),图中有k有向边,…

Will not attempt to authenticate using SASL | dubbo项目启动特别慢,拉取 zookeeper 服务日志打印特别慢

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下使用dubbo遇到的几个问题。 1. cause: KeeperErrorCode ConnectionLoss for /dubbo/ xxx 异常如下&#xff1a; pid9965&qos.accept.foreign.ipfalse&qos.enabletrue&qos.port10887&timestamp1567…

[css] 你有用过table布局吗?说说你的感受

[css] 你有用过table布局吗&#xff1f;说说你的感受 用来做列表排版还是很不错的&#xff0c;但是要想用的好&#xff0c;还是要对table有比较多的了解。 比如实现表头固定&#xff0c;表内容超出滚动的效果等个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放…

Java基础——类加载机制

什么叫类加载 JVM把 .class 字节码文件加载到内存&#xff0c;并进行相关的校验、解析、初始化&#xff0c;最终转换为虚拟机可用的JAVA类型的过程&#xff0c;称为JVM类加载机制。 &#xff08;当然&#xff0c;JVM并不关心class文件的来源&#xff0c;什么&#xff1f;什么叫…

redis集群搭建【简版】

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享一下redis集群安装&#xff0c;写的比较简单&#xff0c;就是做个记录。 1. 下载&安装 wget http://download.redis.io/releases/redis-5.0.4.tar.gz tar -zxvf redis-5.0.4.tar.gz 解压并编译 https://redis.io/ 2.…

[css] 说说你对设备像素比的理解

[css] 说说你对设备像素比的理解 DPR 物理像素与逻辑像素的比个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题