在反序列化JSON数据时,我想防止“ json注入”。 默认情况下,JSON解析器不关心对象中的重复键,而只是覆盖它们。
我花了一些时间来找到可以逆转此行为的功能。 我在杰克逊任职,但在格森却不行。 问题在于项目中有很多代码基于Gson。 因此,切换到杰克逊并不容易。
在杰克逊,此功能称为“ STRICT_DUPLICATE_DETECTION”
{"x": true, "x": false}
答案 0 :(得分:0)
排序。
由于某种原因,Gson在反序列化Map
实例时会检测到名称冲突,但不会对数据包或JsonElement
及其子代进行检查(因此,您无法编写基于树的JSON反序列化器来检测它们) )。
给出
{
"x": true,
"x": false
}
final class Foo {
@SuppressWarnings("UnnecessaryBoxing")
final boolean x = Boolean.valueOf(false);
}
final Foo foo = gson.fromJson(jsonReader, Foo.class);
if ( !foo.x ) {
throw new AssertionError();
}
对于标准JsonReader
,此操作失败。
但是,您可以在最低级别上解决该问题。
这有点棘手,但优化程度不高,但涵盖了所有可能的解串器(这可能解释了Gson在不同的解串器中表现不同的原因:每个这样的解串器都应自己进行此项检查,而只会错过工作)。
final class StrictNamesJsonReader
extends JsonReader {
private final Stack<Set<String>> nameStack = new Stack<>();
private Set<String> names;
private StrictNamesJsonReader(final Reader reader) {
super(reader);
}
static JsonReader of(final Reader reader) {
return new StrictNamesJsonReader(reader);
}
@Override
public void beginObject()
throws IOException {
super.beginObject();
names = new HashSet<>();
nameStack.add(names);
}
@Override
public String nextName()
throws IOException {
final String name = super.nextName();
if ( !names.add(name) ) {
throw new JsonSyntaxException("Detected duplicate property name " + name + " in " + names + " at " + this);
}
return name;
}
@Override
public void endObject()
throws IOException {
super.endObject();
nameStack.pop();
names = !nameStack.isEmpty() ? nameStack.peek() : null;
}
}
如您所见,此JsonReader
实现实现名称重复检测本身的管理,并引发类似以下异常的情况
Exception in thread "main" com.google.gson.JsonSyntaxException: Detected duplicate property name x in [x] at StrictNamesJsonReader at line 3 column 5 path $.x
如果检测到重复。
不过,您可以在https://github.com/google/gson/pull/649上要求修改您的问题。
我确实认为反序列化器是检测重复项的错误方法,与该PR中的建议不同,应该增强JsonReader
。