java - 是否可以通过中间人攻击将代码注入(inject)通过网络传输的 Java 对象?

标签 java serialization reflection network-programming deserialization

在 Java 中,可以执行以下操作通过网络发送和接收对象(不加密)。

class Dog {
    public void bark(){ System.out.println("Woof! Woof!"); }
}

客户端.java

Dog fido = new Dog();
Socket socket = new Socket(new InetSocketAddress("192.168.1.2"), 1234);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(fido);
oos.flush();
oos.close();

服务器.java

ServerSocket server = new ServerSocket(1234);
Socket client = server.accept();
ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
Dog fido = (Dog)ois.readObject();
ois.close();

fido.bark();

我的问题是,假设你已经成功地在两个网络设备之间建立了一个拦截点,这两个设备在不安全的链接上来回发送 Java 对象,并且你知道它们的协议(protocol)并且可以修改它们的数据,是否可以注入(inject) Java 字节将代码写入对象以改变它们的行为?

在我们的小例子中,是否可以让 fido “哞哞!” 而不是吠叫?

最佳答案

当你在 Java 中序列化一个对象时,只有这个对象的字段被序列化。客户端和服务器上的字节码必须相同(或至少兼容)。这是由 serialVersionUID 强制执行的.

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization.

考虑到这一点,如果您更改字段的值,您可以更改行为。鉴于 Dog 的这个实现,您可以拦截请求并将声音的值更改为 "Moo!"

public class Dog {
    private String sound = "Woof! Woof!";
    public void bark(){ System.out.println(sound); }
}

但由于 "Woof!Woof!" 在您的原始实现中是一个编译时常量,它不会被序列化,因为在运行时无法更改它。

关于java - 是否可以通过中间人攻击将代码注入(inject)通过网络传输的 Java 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44838875/

相关文章:

ios - 如何将反射与 Core Data 和 Swift 结合使用

c# - 如何使用反射来调用 DbModelBuilder.Entity<T>.Ignore(x => x.Property)?

java - 使用 Hibernate 表示表关系是个好主意吗?

JAVA随机参数总是返回0

php - 如何控制 json_encode 行为?

Java 序列化与继承?

java - 序列化/反序列化 MQMessage

c# - 如何设置自定义类的反射数组的行

java - 日期格式以长格式给出不同的时间

java - 为什么这里的字符串文字没有被保留?