根据Oracle安全编码指南指南4-1/EEXTEND-1和指南4-5/EEXTEND-5您应该限制类及其成员的可访问性,以防攻击者恶意覆盖。
为继承设计类和方法,或将它们声明为final。左边非final,类或方法可能被攻击者。不允许子类化的类更容易实现并验证它是否安全。
在现实世界中,攻击者如何真正利用以下不安全类?即使类已经加载到正在运行的JVM中,他/她也能做到吗?
public class PasswordVerifier {
private String regex;
public PasswordVerifier(String regex) {
this.regex = regex;
}
public boolean isPasswordValid(String password) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(password);
return matcher.find();
}
public String getRegex() {
return regex;
}
public void setRegex(String regex) {
this.regex = regex;
}
}
如果我们谈论的是一个可以访问源代码的恶意内部人员,难道他一开始就不能删除最后一个修饰符(如果已经有(或通过任何方式更改类本身吗?
无论是否有final
关键字,该代码都是不安全的。它还很大程度上取决于它运行的环境
如果JVM已经在运行:
要困难得多。我确实注意到了通过C++进行注入的一些事情,这可能为在加载类时使用ASM生成/修改运行时类开辟了可能性。这需要将ASM作为依赖项包括在内,而大多数项目都没有这种依赖项。使用此方法,类是否为最终类都无关紧要。从那里,攻击者可以修改isPasswordValid()
方法,使其始终返回true。
如果该类已经加载,我认为这是不可能的。点击此处查看更多信息:
C++在运行的JVM 中调用函数
调用API
我想在运行时更改已经加载的java类。如何做到这一点?
这也提供了一个有趣的阅读:
Java中是否可以进行代码注入?
如果代码被用作库:
容易多了。攻击者可以像您所说的那样删除final
修饰符,也可以使用类似ASM的东西生成一个最初没有final
修饰符的新类。也可以只使用sun.misc.Unsafe
,如这里的repo所示。这将允许他们生成一个新的类,扩展不再是最终类的类。
另一种方法是在加载时只使用ASM来修改类,这会更容易。
可能有更多的方法可以做到这一点,我自己也没有测试过其中的任何一种,但我认为这两种情况都有可能,这取决于环境。
EDIT:我忘了提到,这些东西中的一些可能在Java的后续版本中不起作用,因为在Java的后期版本中,类操作和依赖项访问受到了更大的限制。我把所有这些都建立在你使用Java8的基础上,大多数人仍然这样做
EDIT2:我刚刚在这里找到了这篇文章,它提供了一种通过调试模式执行任意代码的方法,也可以用来操作类。链接