记一次fastjson升级产生的bug

·  阅读 577

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

记录一次fastjson产生的bug

由于fastjson采白名单的方法来防御反序列化满洞,导致当黑客不断发屈新的反序列化Gadgets类时,在autoType关闭的情况下仍然可能可以绕过黑白名单防御机制,造成远程命令执行漏洞。经研究,该漏洞利用门槛较低,可绕过autoType限制,风险影响较大。阿里云应急响应中心提醒fastjson用户尽快采取安全措施阻止漏洞攻击。

但是在升级的过程中,有一个项目出现了问题。出现的问题是,使用大写字母作为属性命名的javaBean,在使用这个方法时出问题。

//parseObject(String text, Class<T> clazz) 
Input input = JSONObject.parseObject(request.getData().toJSONString(), Input.class);
复制代码

上面的代码中,得出来的input为空。

在fastjson的DefaultJSONParser这个类中两个不同版本的fastjson处理选择了不同的方式。

1.2.12

public <T> T parseObject(Type type, Object fieldName) {
    int token = this.lexer.token();
    if (token == 8) {
        this.lexer.nextToken();
        return null;
    } else {
        if (token == 4) {
            if (type == byte[].class) {
                byte[] bytes = this.lexer.bytesValue();
                this.lexer.nextToken();
                return bytes;
            }

            if (type == char[].class) {
                String strVal = this.lexer.stringVal();
                this.lexer.nextToken();
                return strVal.toCharArray();
            }
        }

        ObjectDeserializer derializer = this.config.getDeserializer(type);

        try {
            //这里有所不同
            return derializer.deserialze(this, type, fieldName);
        } catch (JSONException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new JSONException(var7.getMessage(), var7);
        }
    }
}
复制代码

从调试中可以看到,1.2.12版本中属性赋值使用的是通过属性的set方法进行的。

clipboard.png

1.2.70版本

public <T> T parseObject(Type type, Object fieldName) {
    int token = this.lexer.token();
    if (token == 8) {
        this.lexer.nextToken();
        return null;
    } else {
        if (token == 4) {
            if (type == byte[].class) {
                byte[] bytes = this.lexer.bytesValue();
                this.lexer.nextToken();
                return bytes;
            }

            if (type == char[].class) {
                String strVal = this.lexer.stringVal();
                this.lexer.nextToken();
                return strVal.toCharArray();
            }
        }

        ObjectDeserializer deserializer = this.config.getDeserializer(type);

        try {
            if (deserializer.getClass() == JavaBeanDeserializer.class) {
                if (this.lexer.token() != 12 && this.lexer.token() != 14) {
                    throw new JSONException("syntax error,except start with { or [,but actually start with " + this.lexer.tokenName());
                } else {
                //更新后走了这里
                    return ((JavaBeanDeserializer)deserializer).deserialze(this, type, fieldName, 0);
                }
            } else {
            //原来的版本走的是这里
                return deserializer.deserialze(this, type, fieldName);
            }
        } catch (JSONException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new JSONException(var7.getMessage(), var7);
        }
    }
}
复制代码

而1.2.70却是通过这样的方式去解析的。

clipboard.png

最后经过查阅资料,发现可以使用@JSONField(name = "AAA001")这个注解来解决这个问题,在入参的类上进行标注,大写的入参也可以转换了。

@JSONField(name = "AAA001)
private String AAA001; //属性1
复制代码

同时有部分人因为使用lombok插件,导致@JSONField(name = "AAA001")标注在属性上依旧不起作用,此时可以通过显示声明属性的get方法来达成目的。

    @JSONField(name = "AAA001")
    public String getAAA001() {
        return AAA001;
    }
复制代码
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改