限制 类 及其成员的可访问性是否是更安全代码的有效做法?
Is limitation of accessibility for classes and their members a valid practice for more secure code?
根据 Oracle 安全编码指南 指南 4-1/EXTEND-1 和指南 4-5/EXTEND-5
您应该限制 classes 及其成员的可访问性,作为防止攻击者恶意覆盖的安全控制措施。
Design classes and methods for inheritance or declare them final. Left
non-final, a class or method can be maliciously overridden by an
attacker. A class that does not permit subclassing is easier to
implement and verify that it is secure.
攻击者如何在真实场景中实际利用以下不安全 class?
即使 class 已经加载到 运行 JVM 中,he/she 也能做到吗?
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;
}
}
如果我们谈论的是一个可以访问源代码的恶意内部人员,他不能删除最终修饰符(如果已经存在的话)或以任何方式更改 class 本身第一名?
无论是否有 final
关键字,该代码都不安全。它还在很大程度上取决于它 运行 所在的环境。
如果JVM已经是运行:
困难多了。我确实注意到通过 C++ 注入的一些事情,这可能会打开运行时 class generation/modification 和 ASM 之类的东西的可能性,因为 class 正在加载。这将需要将 ASM 作为依赖项包含在内,而大多数项目都没有。使用这种方法,class 是否为 final 并不重要。从那里,攻击者只需将 isPasswordValid()
方法修改为始终 return true.
如果 class 已经加载,我认为这是不可能的。在这里查看更多信息:
I want to change java class at run time which is already loaded. how to do this?
这也提供了一个有趣的读物:
Is code injection possible in Java?
如果代码被用作库:
容易多了。攻击者可以像你说的那样删除 final
修饰符,或者生成一个新的 class 像 ASM 这样一开始就没有 final
修饰符的东西。也可以只使用 sun.misc.Unsafe
,如本回购 here 所示。这将允许他们生成一个新的 class 来扩展不再是最终的 class.
另一种方法是在 class 加载时使用 ASM 修改它,这样会更容易。
可能还有更多的方法,我自己还没有实际测试过,但我认为这两种情况都可以,具体取决于环境。
编辑: 我忘了提到这些东西中的一些可能在 Java 的更高版本中不起作用,其中 class 操作和依赖访问是限制多了。我所有这些都是基于你使用 Java 8,大多数人仍然这样做。
编辑 2:
我刚刚在这里找到这篇文章,它提供了一种通过调试模式执行任意代码的方法,它也可以用来操作 class 。 Link
根据 Oracle 安全编码指南 指南 4-1/EXTEND-1 和指南 4-5/EXTEND-5 您应该限制 classes 及其成员的可访问性,作为防止攻击者恶意覆盖的安全控制措施。
Design classes and methods for inheritance or declare them final. Left non-final, a class or method can be maliciously overridden by an attacker. A class that does not permit subclassing is easier to implement and verify that it is secure.
攻击者如何在真实场景中实际利用以下不安全 class? 即使 class 已经加载到 运行 JVM 中,he/she 也能做到吗?
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;
}
}
如果我们谈论的是一个可以访问源代码的恶意内部人员,他不能删除最终修饰符(如果已经存在的话)或以任何方式更改 class 本身第一名?
无论是否有 final
关键字,该代码都不安全。它还在很大程度上取决于它 运行 所在的环境。
如果JVM已经是运行:
困难多了。我确实注意到通过 C++ 注入的一些事情,这可能会打开运行时 class generation/modification 和 ASM 之类的东西的可能性,因为 class 正在加载。这将需要将 ASM 作为依赖项包含在内,而大多数项目都没有。使用这种方法,class 是否为 final 并不重要。从那里,攻击者只需将 isPasswordValid()
方法修改为始终 return true.
如果 class 已经加载,我认为这是不可能的。在这里查看更多信息:
I want to change java class at run time which is already loaded. how to do this?
这也提供了一个有趣的读物:
Is code injection possible in Java?
如果代码被用作库:
容易多了。攻击者可以像你说的那样删除 final
修饰符,或者生成一个新的 class 像 ASM 这样一开始就没有 final
修饰符的东西。也可以只使用 sun.misc.Unsafe
,如本回购 here 所示。这将允许他们生成一个新的 class 来扩展不再是最终的 class.
另一种方法是在 class 加载时使用 ASM 修改它,这样会更容易。
可能还有更多的方法,我自己还没有实际测试过,但我认为这两种情况都可以,具体取决于环境。
编辑: 我忘了提到这些东西中的一些可能在 Java 的更高版本中不起作用,其中 class 操作和依赖访问是限制多了。我所有这些都是基于你使用 Java 8,大多数人仍然这样做。
编辑 2: 我刚刚在这里找到这篇文章,它提供了一种通过调试模式执行任意代码的方法,它也可以用来操作 class 。 Link