2 Answers
-
0
- Nguyên nhân ra đời
Ngày xưa chưa có sự ra đời của protobuf hay message pack, hay json, xml như ngày nay, mà khi gửi nhận qua mạng hay lưu dữ liệu thì phải biến object thành byte array đúng không nhỉ? Vậy thì ông Java phải viết riêng thư viện serialize và deserialize cho mình rồi. Tuy nhiên lại có vấn đề thế này:
Chúng ta có 2 lớp giống hệt nhau về tên gói, tên lớp và serialVersionUID kiểu:
// đây là lớp của chúng ta class A implements Serializable { private static final long serialVersionUID = 2L; String name; String value; }
// đây là lớp của hacker đã xoá mất trường name để nhằm mục tiêu chiếm đoạt giá trị value class A implements Serializable { private static final long serialVersionUID = 2L; String value; }
Rõ ràng là khi hacker dùng đoạn code này:
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); A a = new A(); a.value = "Hello"; out.writeObject(a); byte[] bytes = byteOut.toByteArray();
Kết quả sẽ là 1 byte array: [-84, -19, 0, 5, 115, 114, 0, 52, 99, 111, 109, 46, 116, 118, 100, 49, 50, 46, 101, 120, 97, 109, 112, 108, 101, 46, 115, 101, 114, 105, 97, 108, 105, 122, 101, 114, 46, 74, 97, 118, 97, 83, 101, 114, 105, 97, 108, 105, 122, 101, 114, 69, 120, 97, 109, 112, 108, 101, 36, 65, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 76, 0, 5, 118, 97, 108, 117, 101, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 120, 112, 116, 0, 5, 72, 101, 108, 108, 111]
Và gửi cái mảng byte này đến rmi server, rmi server sẽ deserialize kiểu này:
ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes); ObjectInputStream in = new ObjectInputStream(byteIn); A a = (A)in.readObject();
thì bản thân rmi server sẽ không thể biết được là dữ liệu byte array kia là do ai gửi, đến từ đâu, vì cùng lớp, cùng serialVersionUID nên server sẽ chấp nhận dữ liệu của hacker. Vậy nên phải sinh ra serialVersionUID khác nhau để thêm 1 bước nữa kiểm tra tính hợp lệ của dữ liệu. Trong trường hợp này, nếu lớp của hacker là:
public static class A implements Serializable { private static final long serialVersionUID = 3L; public String value; }
Thì kết quả ở trên server sẽ là:
Exception in thread "main" java.io.InvalidClassException: com.tvd12.example.serializer.JavaSerializerExample$A; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = 3 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459) at com.tvd12.example.serializer.JavaSerializerExample.main(JavaSerializerExample.java:26)
- Ứng dụng ngày nay
Ngày nay thi chúng ta có các thư viện serialize + package message khủng hơn rất nhiều rồi như protobuf, message pack, mà cũng không còn nhiều người dùng đến rmi hay các server của java nữa, nên em có thể bỏ qua nó cũng được, nếu có exception thì thêm vào cũng không sao
-
2