限制 类 及其成员的可访问性是否是更安全代码的有效做法?

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 已经加载,我认为这是不可能的。在这里查看更多信息:

The Invocation API

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