Skip to content

Commit 2cf10a7

Browse files
authored
Merge pull request #4427 from aschackmull/java/fastjson
Java: Add support for FastJson in unsafe deserialization.
2 parents 9156163 + 4be731d commit 2cf10a7

File tree

13 files changed

+399
-1
lines changed

13 files changed

+399
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
lgtm,codescanning
2+
* The "Deserialization of user-controlled data" (`java/unsafe-deserialization`) query
3+
now recognizes `FastJson` deserialization.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Provides classes and predicates for working with the FastJson framework.
3+
*/
4+
5+
import java
6+
7+
/**
8+
* The class `com.alibaba.fastjson.JSON`.
9+
*/
10+
class FastJson extends RefType {
11+
FastJson() { this.hasQualifiedName("com.alibaba.fastjson", "JSON") }
12+
}
13+
14+
/**
15+
* A FastJson parse method. This is either `JSON.parse` or `JSON.parseObject`.
16+
*/
17+
class FastJsonParseMethod extends Method {
18+
FastJsonParseMethod() {
19+
this.getDeclaringType() instanceof FastJson and
20+
this.hasName(["parse", "parseObject"])
21+
}
22+
}
23+
24+
/**
25+
* A call to `ParserConfig.setSafeMode`.
26+
*/
27+
class FastJsonSetSafeMode extends MethodAccess {
28+
FastJsonSetSafeMode() {
29+
exists(Method m |
30+
this.getMethod() = m and
31+
m.hasName("setSafeMode") and
32+
m.getDeclaringType().hasQualifiedName("com.alibaba.fastjson.parser", "ParserConfig")
33+
)
34+
}
35+
36+
/** Gets the constant value passed to this call, if any. */
37+
boolean getMode() { result = this.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() }
38+
}
39+
40+
/**
41+
* Holds if there is some call to `ParserConfig.setSafeMode` that does not
42+
* explicitly disable safe mode.
43+
*/
44+
predicate fastJsonLooksSafe() {
45+
exists(FastJsonSetSafeMode setsafe | not setsafe.getMode() = false)
46+
}

java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import semmle.code.java.frameworks.Kryo
22
import semmle.code.java.frameworks.XStream
33
import semmle.code.java.frameworks.SnakeYaml
4+
import semmle.code.java.frameworks.FastJson
45
import semmle.code.java.frameworks.apache.Lang
56

67
class ObjectInputStreamReadObjectMethod extends Method {
@@ -77,6 +78,10 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
7778
or
7879
ma instanceof UnsafeSnakeYamlParse and
7980
sink = ma.getArgument(0)
81+
or
82+
ma.getMethod() instanceof FastJsonParseMethod and
83+
not fastJsonLooksSafe() and
84+
sink = ma.getArgument(0)
8085
)
8186
}
8287

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import java.io.*;
2+
import java.net.Socket;
3+
import com.alibaba.fastjson.JSON;
4+
5+
public class B {
6+
public Object deserializeJson1(Socket sock) {
7+
InputStream inputStream = sock.getInputStream();
8+
return JSON.parseObject(inputStream, null); // unsafe
9+
}
10+
11+
public Object deserializeJson2(Socket sock) {
12+
InputStream inputStream = sock.getInputStream();
13+
byte[] bytes = new byte[100];
14+
inputStream.read(bytes);
15+
return JSON.parse(bytes); // unsafe
16+
}
17+
18+
public Object deserializeJson3(Socket sock) {
19+
InputStream inputStream = sock.getInputStream();
20+
byte[] bytes = new byte[100];
21+
inputStream.read(bytes);
22+
String s = new String(bytes);
23+
return JSON.parseObject(s); // unsafe
24+
}
25+
26+
public Object deserializeJson4(Socket sock) {
27+
InputStream inputStream = sock.getInputStream();
28+
byte[] bytes = new byte[100];
29+
inputStream.read(bytes);
30+
String s = new String(bytes);
31+
return JSON.parse(s); // unsafe
32+
}
33+
}

java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ edges
1616
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) |
1717
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input |
1818
| A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) |
19+
| B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream |
20+
| B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes |
21+
| B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s |
22+
| B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:31:23:31:23 | s |
1923
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
2024
nodes
2125
| A.java:13:31:13:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
@@ -42,6 +46,14 @@ nodes
4246
| A.java:73:28:73:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
4347
| A.java:74:24:74:28 | input | semmle.label | input |
4448
| A.java:75:24:75:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) |
49+
| B.java:7:31:7:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
50+
| B.java:8:29:8:39 | inputStream | semmle.label | inputStream |
51+
| B.java:12:31:12:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
52+
| B.java:15:23:15:27 | bytes | semmle.label | bytes |
53+
| B.java:19:31:19:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
54+
| B.java:23:29:23:29 | s | semmle.label | s |
55+
| B.java:27:31:27:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
56+
| B.java:31:23:31:23 | s | semmle.label | s |
4557
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | semmle.label | entityStream : InputStream |
4658
| TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | semmle.label | new ObjectInputStream(...) |
4759
#select
@@ -62,4 +74,8 @@ nodes
6274
| A.java:73:17:73:56 | parse(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
6375
| A.java:74:12:74:38 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
6476
| A.java:75:12:75:61 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input |
77+
| B.java:8:12:8:46 | parseObject(...) | B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream | Unsafe deserialization of $@. | B.java:7:31:7:51 | getInputStream(...) | user input |
78+
| B.java:15:12:15:28 | parse(...) | B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes | Unsafe deserialization of $@. | B.java:12:31:12:51 | getInputStream(...) | user input |
79+
| B.java:23:12:23:30 | parseObject(...) | B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s | Unsafe deserialization of $@. | B.java:19:31:19:51 | getInputStream(...) | user input |
80+
| B.java:31:12:31:24 | parse(...) | B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:31:23:31:23 | s | Unsafe deserialization of $@. | B.java:27:31:27:51 | getInputStream(...) | user input |
6581
| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright 1999-2017 Alibaba Group.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.alibaba.fastjson;
17+
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
import java.lang.reflect.Type;
21+
import java.nio.charset.Charset;
22+
import java.nio.charset.CharsetDecoder;
23+
import java.util.*;
24+
25+
import com.alibaba.fastjson.parser.*;
26+
import com.alibaba.fastjson.parser.deserializer.ParseProcess;
27+
28+
public abstract class JSON {
29+
public static Object parse(String text) {
30+
return null;
31+
}
32+
33+
public static Object parse(String text, ParserConfig config) {
34+
return null;
35+
}
36+
37+
public static Object parse(String text, ParserConfig config, Feature... features) {
38+
return null;
39+
}
40+
41+
public static Object parse(String text, ParserConfig config, int features) {
42+
return null;
43+
}
44+
45+
public static Object parse(String text, int features) {
46+
return null;
47+
}
48+
49+
public static Object parse(byte[] input, Feature... features) {
50+
return null;
51+
}
52+
53+
public static Object parse(byte[] input, int off, int len, CharsetDecoder charsetDecoder, Feature... features) {
54+
return null;
55+
}
56+
57+
public static Object parse(byte[] input, int off, int len, CharsetDecoder charsetDecoder, int features) {
58+
return null;
59+
}
60+
61+
public static Object parse(String text, Feature... features) {
62+
return null;
63+
}
64+
65+
public static JSONObject parseObject(String text, Feature... features) {
66+
return null;
67+
}
68+
69+
public static JSONObject parseObject(String text) {
70+
return null;
71+
}
72+
73+
public static <T> T parseObject(String text, TypeReference<T> type, Feature... features) {
74+
return null;
75+
}
76+
77+
public static <T> T parseObject(String json, Class<T> clazz, Feature... features) {
78+
return null;
79+
}
80+
81+
public static <T> T parseObject(String text, Class<T> clazz, ParseProcess processor, Feature... features) {
82+
return null;
83+
}
84+
85+
public static <T> T parseObject(String json, Type type, Feature... features) {
86+
return null;
87+
}
88+
89+
public static <T> T parseObject(String input, Type clazz, ParseProcess processor, Feature... features) {
90+
return null;
91+
}
92+
93+
public static <T> T parseObject(String input, Type clazz, int featureValues, Feature... features) {
94+
return null;
95+
}
96+
97+
public static <T> T parseObject(String input, Type clazz, ParserConfig config, Feature... features) {
98+
return null;
99+
}
100+
101+
public static <T> T parseObject(String input, Type clazz, ParserConfig config, int featureValues,
102+
Feature... features) {
103+
return null;
104+
}
105+
106+
public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor,
107+
int featureValues, Feature... features) {
108+
return null;
109+
}
110+
111+
public static <T> T parseObject(byte[] bytes, Type clazz, Feature... features) {
112+
return null;
113+
}
114+
115+
public static <T> T parseObject(byte[] bytes, int offset, int len, Charset charset, Type clazz, Feature... features) {
116+
return null;
117+
}
118+
119+
public static <T> T parseObject(byte[] bytes,
120+
Charset charset,
121+
Type clazz,
122+
ParserConfig config,
123+
ParseProcess processor,
124+
int featureValues,
125+
Feature... features) {
126+
return null;
127+
}
128+
129+
public static <T> T parseObject(byte[] bytes, int offset, int len,
130+
Charset charset,
131+
Type clazz,
132+
ParserConfig config,
133+
ParseProcess processor,
134+
int featureValues,
135+
Feature... features) {
136+
return null;
137+
}
138+
139+
public static <T> T parseObject(byte[] input,
140+
int off,
141+
int len,
142+
CharsetDecoder charsetDecoder,
143+
Type clazz,
144+
Feature... features) {
145+
return null;
146+
}
147+
148+
public static <T> T parseObject(char[] input, int length, Type clazz, Feature... features) {
149+
return null;
150+
}
151+
152+
public static <T> T parseObject(InputStream is,
153+
Type type,
154+
Feature... features) throws IOException {
155+
return null;
156+
}
157+
158+
public static <T> T parseObject(InputStream is,
159+
Charset charset,
160+
Type type,
161+
Feature... features) throws IOException {
162+
return null;
163+
}
164+
165+
public static <T> T parseObject(InputStream is,
166+
Charset charset,
167+
Type type,
168+
ParserConfig config,
169+
Feature... features) throws IOException {
170+
return null;
171+
}
172+
173+
public static <T> T parseObject(InputStream is,
174+
Charset charset,
175+
Type type,
176+
ParserConfig config,
177+
ParseProcess processor,
178+
int featureValues,
179+
Feature... features) throws IOException {
180+
return null;
181+
}
182+
183+
public static <T> T parseObject(String text, Class<T> clazz) {
184+
return null;
185+
}
186+
187+
public static JSONArray parseArray(String text) {
188+
return null;
189+
}
190+
191+
public static JSONArray parseArray(String text, ParserConfig parserConfig) {
192+
return null;
193+
}
194+
195+
public static <T> List<T> parseArray(String text, Class<T> clazz) {
196+
return null;
197+
}
198+
199+
public static <T> List<T> parseArray(String text, Class<T> clazz, ParserConfig config) {
200+
return null;
201+
}
202+
203+
public static List<Object> parseArray(String text, Type[] types) {
204+
return null;
205+
}
206+
207+
public static List<Object> parseArray(String text, Type[] types, ParserConfig config) {
208+
return null;
209+
}
210+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 1999-2017 Alibaba Group.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.alibaba.fastjson;
17+
18+
public class JSONArray extends JSON {
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 1999-2017 Alibaba Group.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.alibaba.fastjson;
17+
18+
public class JSONObject extends JSON {
19+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.alibaba.fastjson;
2+
3+
public class TypeReference<T> {
4+
}

0 commit comments

Comments
 (0)