如何发现java反序列化问题?
我希望能够发现java代码中反序列化的问题。我应该寻找什么?例如,如何确定某些 java 代码是否尝试利用“java 日历错误< /a>”?请注意,我不是 java 程序员,但我很好地理解序列化和 OOP 背后的概念。我正在尝试实施一些安全检查(例如编译器警告工具)。
编辑:根据评论我想稍微改变一下问题: 我认为所有分析的代码都是“不可信的”,有没有办法评估潜在的危险?我的意思是,就反序列化错误而言,我可以说代码 A 比 B 更危险吗?我应该寻找什么?
i would like to be able to spot problems with deserialization in java code. What should i look for? For example, how would one determine if some java code tries to exploit "java calendar bug"? Note that i'm not a java programmer, but i understand the concepts behind serialization and OOP fine. I'm trying to implement some safety checks (something like a compiler warning tool).
EDIT: based on comments i would like to change the question a bit:
I consider all the code analyzed "untrusted", is there a way how to rate the potential danger? I mean, can i tell that code A is more dangerous than B with regard to deserialization bug? What should i look for?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,您需要了解您的上下文以确定安全威胁。 (当我谈论“信任”时,我没有走捷径。我说的是故意恶意。)
如果以相同的信任创建、保存和读取序列化数据,那么就不存在任何真正的问题(其他)比标准错误)。请注意,如果您写入任何敏感信息,那么序列化数据也是敏感的(这似乎很明显,但其中存在大量间接信息)。
如果序列化数据由于某种原因不受信任,那么还需要考虑更多。重新创建的对象的内部结构可能是“不寻常的”。数据可能不一致。您可能拥有共享的可变对象,这些对象应该是单独的。反序列化可能会导致无限循环,或者恰好在宇宙热寂之前无法完成的非无限循环。当然,数据也可能是谎言。
如果您正在编写由不太受信任的代码使用的库代码,那么事情会变得更有趣:
在“日历错误”(和类似的)的情况下,这是关于用恶意数据和恶意代码反序列化任意流。 Java 安全编码指南建议在自定义
readObject
方法中进行安全检查(使用“Java2 安全模型”),这意味着您不应比代码和数据更信任地调用反序列化。从可反序列化对象的角度来看,事情更加棘手。
ObjectInputStream
通过readObject
、readUnshared
、defaultReadObject
、readFields
提供的对象,或者只是默认反序列化可能具有被恶意代码捕获的引用,或者对于非最终类,被恶意子类化。当部分初始化时,对象也可以在反序列化期间使用。反序列化不会调用反序列化类的“真正”构造函数(readObject
/readObjectNoData
是一种伪构造函数,无法设置final
代码>s)。这有点像一场噩梦,所以您可能不想让您的敏感类可序列化。序列化和反序列化的实现中存在许多漏洞。您实际上不需要担心这一点,除非您自己实现它。
Firstly you need to understand your context to determine security threats. (When I talk about "trust", I'm taking little short cut. I'm talking deliberately malicious.)
If the serialised data was created, kept and read with the same trust, then there isn't any real problem (other than standard bugs). Note if you write any sensitive information, then the serialised data is also sensitive (it seems obvious, but there is a fair amount of indirection there).
If the the serialised data is untrusted for whatever reason, then there is a little more to consider. The internal structure of the recreated objects may be "unusual". The data may not be consistent. You may have shared mutable objects which should be separate. Deserialisation may cause an infinite loop, or a non-infinite loop which just happens not to be completable before the heat death of the universe. And of course the data may be lies.
If you are writing library code that is used by less trusted code, then things get more interesting:
In the case of "calendar bug" (and similar), that is about deserialising an arbitrary stream with malicious data and malicious code. The Java Secure Coding Guidelines suggests doing security checks (using the "Java2 Security Model") within custom
readObject
methods, which implies that you shouldn't call deserialisation with more trust than the code and data has.From the side of deserialisable objects, things are more tricky. Objects provided by
ObjectInputStream
throughreadObject
,readUnshared
,defaultReadObject
,readFields
or just the default deserialisation may have references captured by malicious code or, for non-final classes, be subclassed maliciously. An object may also be used during deserialisation, when partially initialised. Deserialisation does not invoke a "real" constructor of the deserialised class (readObject
/readObjectNoData
is a kind of psuedo-constructor, which can't setfinal
s). It's all a bit of a nightmare, so you probably don't want to make your sensitive classes serialisable.There have been a number of vulnerabilities in the implementation of serialisation and deserialisation. You don't really need to worry about this, unless you are implementing it yourself.
嗯……你的问题有点笼统。您是否看过这篇文章?这是关于 Java 的序列化算法,但来自 Google 的缓存,因为主页目前似乎已关闭。
Hmm... your question is a bit general. Did you take a look at this article? It's about Java's serialization algorithm, but from Google's cache because the main page seems to be down at the moment.
我认为,击败利用 Java 中已知安全漏洞的代码的最佳方法是升级到修复该错误的 Java 版本。下一个最佳方法(处理序列化相关的错误)是将来自未知/未经验证/不安全来源的所有序列化数据视为可疑。
尝试通过分析 Java 代码中的安全错误来发现问题并不容易,并且需要深入了解正在使用和可能被利用的 Java 机制。尝试发现尝试的漏洞(一般而言)会更加困难,特别是如果您正在寻找零日安全漏洞的漏洞。请记住,还有其他潜在的向量。
(如果有简单的方法可以找到 Java 中未知的安全漏洞,那么您可以打赌 Sun 和其他安全研究人员已经使用了它们。)
I'd have thought that the best way to defeat code that exploits known security holes in Java is to upgrade to a Java version that fixes the bug. And the next best way (to deal with serialization related bugs) is treat all serialized data from unknown / unverified / insecure sources as suspicious.
Trying to spot problems by analyzing java code for security bugs isn't easy, and requires a deep understanding of the Java mechanisms that are being used and could be exploited. Trying to spot attempted exploits (in general) would be even harder, especially if you are looking for exploits for zero-day security holes. Bear in mind that there are other potential vectors.
(If there were easy ways to find unknown security holes in Java, you can bet that Sun and other security researchers would have already used them.)
如果您序列化 Java 对象以将其传输到单独的应用程序,为什么不考虑使用应用程序之间共享的密钥对该对象进行签名呢?它应该足以保护自己免受中间人攻击。
回到验证问题的核心,验证对于通用语言来说是极其困难的。您应该寻找有关该主题的科学出版物。我认为最常用的技术是沙箱。第二种方法是限制语言并禁止执行危险命令,例如 Yahoo Caja 库 使用这种技术。
If you serialize your Java object to transfer it to a separated application, why not consider signing the object with a key shared between applications? It should be enough to defend yourself from man-in-the-middle attack.
Going back to the core of the verification problem, the verification is extremely difficult for general purpose languages. You should look for scientific publications on this topic. I think the most commonly applied technique is sandboxing. The second approach is to restrict the language and disallow the execution of dangerous commands, e.g., Yahoo Caja library uses this technique.