Skip to content

Commit fa8e539

Browse files
committed
SimpleHttpResponse adds deserialization whitelist
1 parent be646f7 commit fa8e539

File tree

3 files changed

+95
-16
lines changed

3 files changed

+95
-16
lines changed

tunnel-common/pom.xml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@
1212
<url>https://github.com/alibaba/arthas</url>
1313

1414
<dependencies>
15-
16-
15+
<dependency>
16+
<groupId>junit</groupId>
17+
<artifactId>junit</artifactId>
18+
<scope>test</scope>
19+
</dependency>
20+
<dependency>
21+
<groupId>org.assertj</groupId>
22+
<artifactId>assertj-core</artifactId>
23+
<scope>test</scope>
24+
</dependency>
1725
</dependencies>
1826

1927
<build>

tunnel-common/src/main/java/com/alibaba/arthas/tunnel/common/SimpleHttpResponse.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import java.io.ByteArrayInputStream;
44
import java.io.ByteArrayOutputStream;
55
import java.io.IOException;
6-
import java.io.ObjectInput;
6+
import java.io.InvalidClassException;
77
import java.io.ObjectInputStream;
88
import java.io.ObjectOutputStream;
9+
import java.io.ObjectStreamClass;
910
import java.io.Serializable;
11+
import java.util.Arrays;
1012
import java.util.HashMap;
13+
import java.util.List;
1114
import java.util.Map;
1215

1316
/**
@@ -16,9 +19,11 @@
1619
*
1720
*/
1821
public class SimpleHttpResponse implements Serializable {
19-
2022
private static final long serialVersionUID = 1L;
2123

24+
private static final List<String> whitelist = Arrays.asList(byte[].class.getName(), String.class.getName(),
25+
Map.class.getName(), HashMap.class.getName(), SimpleHttpResponse.class.getName());
26+
2227
private int status = 200;
2328

2429
private Map<String, String> headers = new HashMap<String, String>();
@@ -62,27 +67,28 @@ public static byte[] toBytes(SimpleHttpResponse response) throws IOException {
6267
out.flush();
6368
return bos.toByteArray();
6469
} finally {
65-
try {
66-
bos.close();
67-
} catch (IOException ex) {
68-
// ignore close exception
70+
if (out != null) {
71+
out.close();
6972
}
7073
}
7174
}
7275

7376
public static SimpleHttpResponse fromBytes(byte[] bytes) throws IOException, ClassNotFoundException {
7477
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
75-
ObjectInput in = null;
78+
ObjectInputStream in = null;
7679
try {
77-
in = new ObjectInputStream(bis);
80+
in = new ObjectInputStream(bis) {
81+
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
82+
if (!whitelist.contains(desc.getName())) {
83+
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
84+
}
85+
return super.resolveClass(desc);
86+
}
87+
};
7888
return (SimpleHttpResponse) in.readObject();
7989
} finally {
80-
try {
81-
if (in != null) {
82-
in.close();
83-
}
84-
} catch (IOException ex) {
85-
// ignore close exception
90+
if (in != null) {
91+
in.close();
8692
}
8793
}
8894
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.alibaba.arthas.tunnel.common;
2+
3+
import static org.junit.Assert.assertArrayEquals;
4+
import static org.junit.Assert.assertEquals;
5+
6+
import java.io.ByteArrayOutputStream;
7+
import java.io.IOException;
8+
import java.io.InvalidClassException;
9+
import java.io.ObjectOutputStream;
10+
import java.util.Date;
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
14+
import org.junit.Test;
15+
16+
public class SimpleHttpResponseTest {
17+
18+
@Test
19+
public void testSerialization() throws IOException, ClassNotFoundException {
20+
SimpleHttpResponse response = new SimpleHttpResponse();
21+
response.setStatus(200);
22+
23+
Map<String, String> headers = new HashMap<String, String>();
24+
headers.put("Content-Type", "text/plain");
25+
response.setHeaders(headers);
26+
27+
String content = "Hello, world!";
28+
response.setContent(content.getBytes());
29+
30+
byte[] bytes = SimpleHttpResponse.toBytes(response);
31+
32+
SimpleHttpResponse deserializedResponse = SimpleHttpResponse.fromBytes(bytes);
33+
34+
assertEquals(response.getStatus(), deserializedResponse.getStatus());
35+
assertEquals(response.getHeaders(), deserializedResponse.getHeaders());
36+
assertArrayEquals(response.getContent(), deserializedResponse.getContent());
37+
}
38+
39+
public static byte[] toBytes(Object response) throws IOException {
40+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
41+
ObjectOutputStream out = null;
42+
try {
43+
out = new ObjectOutputStream(bos);
44+
out.writeObject(response);
45+
out.flush();
46+
return bos.toByteArray();
47+
} finally {
48+
if (out != null) {
49+
out.close();
50+
}
51+
}
52+
}
53+
54+
@Test(expected = InvalidClassException.class)
55+
public void testDeserializationWithUnauthorizedClass() throws IOException, ClassNotFoundException {
56+
Date date = new Date();
57+
58+
byte[] bytes = toBytes(date);
59+
60+
// Try to deserialize the object with an unauthorized class
61+
// This should throw an InvalidClassException
62+
SimpleHttpResponse.fromBytes(bytes);
63+
}
64+
65+
}

0 commit comments

Comments
 (0)