diff --git a/java/change-notes/2020-10-07-fastjson-deserialization-sink.md b/java/change-notes/2020-10-07-fastjson-deserialization-sink.md new file mode 100644 index 00000000000..12884db0c54 --- /dev/null +++ b/java/change-notes/2020-10-07-fastjson-deserialization-sink.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The "Deserialization of user-controlled data" (`java/unsafe-deserialization`) query + now recognizes `FastJson` deserialization. diff --git a/java/ql/src/semmle/code/java/frameworks/FastJson.qll b/java/ql/src/semmle/code/java/frameworks/FastJson.qll new file mode 100644 index 00000000000..9b4f37b2493 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/FastJson.qll @@ -0,0 +1,50 @@ +/** + * Provides classes and predicates for working with the FastJson framework. + */ + +import java + +/** + * The class `com.alibaba.fastjson.JSON` or `com.alibaba.fastjson.JSONObject`. + */ +class FastJson extends RefType { + FastJson() { + this.hasQualifiedName("com.alibaba.fastjson", "JSON") or + this.hasQualifiedName("com.alibaba.fastjson", "JSONObject") + } +} + +/** + * A FastJson parse method. This is either `parse` or `parseObject` on either + * `com.alibaba.fastjson.JSON` or `com.alibaba.fastjson.JSONObject`. + */ +class FastJsonParseMethod extends Method { + FastJsonParseMethod() { + this.getDeclaringType() instanceof FastJson and + this.hasName(["parse", "parseObject"]) + } +} + +/** + * A call to `ParserConfig.setSafeMode`. + */ +class FastJsonSetSafeMode extends MethodAccess { + FastJsonSetSafeMode() { + exists(Method m | + this.getMethod() = m and + m.hasName("setSafeMode") and + m.getDeclaringType().hasQualifiedName("com.alibaba.fastjson.parser", "ParserConfig") + ) + } + + /** Gets the constant value passed to this call, if any. */ + boolean getMode() { result = this.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() } +} + +/** + * Holds if there is some call to `ParserConfig.setSafeMode` that does not + * explicitly disable safe mode. + */ +predicate fastJsonLooksSafe() { + exists(FastJsonSetSafeMode setsafe | not setsafe.getMode() = false) +} diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll index 482eabc4c61..4aaaa5e25e1 100644 --- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll +++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll @@ -1,6 +1,7 @@ import semmle.code.java.frameworks.Kryo import semmle.code.java.frameworks.XStream import semmle.code.java.frameworks.SnakeYaml +import semmle.code.java.frameworks.FastJson import semmle.code.java.frameworks.apache.Lang class ObjectInputStreamReadObjectMethod extends Method { @@ -77,6 +78,10 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) { or ma instanceof UnsafeSnakeYamlParse and sink = ma.getArgument(0) + or + ma.getMethod() instanceof FastJsonParseMethod and + not fastJsonLooksSafe() and + sink = ma.getArgument(0) ) }