Skip to content

Commit

Permalink
SimpleHttpResponse adds deserialization whitelist
Browse files Browse the repository at this point in the history
  • Loading branch information
hengyunabc committed Aug 2, 2023
1 parent af70d95 commit 76fef20
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 23 deletions.
12 changes: 10 additions & 2 deletions tunnel-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@
<url>https://github.com/alibaba/arthas</url>

<dependencies>


<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
Expand All @@ -16,9 +19,11 @@
*
*/
public class SimpleHttpResponse implements Serializable {

private static final long serialVersionUID = 1L;

private static final List<String> whitelist = Arrays.asList(byte[].class.getName(), String.class.getName(),
Map.class.getName(), HashMap.class.getName(), SimpleHttpResponse.class.getName());

private int status = 200;

private Map<String, String> headers = new HashMap<String, String>();
Expand Down Expand Up @@ -55,35 +60,25 @@ public void setStatus(int status) {

public static byte[] toBytes(SimpleHttpResponse response) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
try (ObjectOutputStream out = new ObjectOutputStream(bos)) {
out.writeObject(response);
out.flush();
return bos.toByteArray();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
}

public static SimpleHttpResponse fromBytes(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
return (SimpleHttpResponse) in.readObject();
} finally {
try {
if (in != null) {
in.close();
try (ObjectInputStream in = new ObjectInputStream(bis) {
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!whitelist.contains(desc.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
} catch (IOException ex) {
// ignore close exception
return super.resolveClass(desc);
}
}) {
return (SimpleHttpResponse) in.readObject();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.alibaba.arthas.tunnel.common;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectOutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

public class SimpleHttpResponseTest {

@Test
public void testSerialization() throws IOException, ClassNotFoundException {
SimpleHttpResponse response = new SimpleHttpResponse();
response.setStatus(200);

Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "text/plain");
response.setHeaders(headers);

String content = "Hello, world!";
response.setContent(content.getBytes());

byte[] bytes = SimpleHttpResponse.toBytes(response);

SimpleHttpResponse deserializedResponse = SimpleHttpResponse.fromBytes(bytes);

assertEquals(response.getStatus(), deserializedResponse.getStatus());
assertEquals(response.getHeaders(), deserializedResponse.getHeaders());
assertArrayEquals(response.getContent(), deserializedResponse.getContent());
}

private static byte[] toBytes(Object object) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bos)) {
out.writeObject(object);
out.flush();
return bos.toByteArray();
}
}

@Test(expected = InvalidClassException.class)
public void testDeserializationWithUnauthorizedClass() throws IOException, ClassNotFoundException {
Date date = new Date();

byte[] bytes = toBytes(date);

// Try to deserialize the object with an unauthorized class
// This should throw an InvalidClassException
SimpleHttpResponse.fromBytes(bytes);
}

}

0 comments on commit 76fef20

Please sign in to comment.