首页 > 解决方案 > 限制类及其成员的可访问性是否是更安全代码的有效做法?

问题描述

根据Oracle 安全编码指南指南 4-1/EXTEND-1 和指南 4-5/EXTEND-5,您应该限制类及其成员的可访问性,作为防止攻击者恶意覆盖的安全控制。

设计继承的类和方法或将它们声明为 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 修饰符(如果已经存在的话)或以任何方式改变类本身吗?

标签: javasecurityimmutabilitysecure-coding

解决方案


无论是否有final关键字,该代码都不安全。它还很大程度上取决于它运行的环境。

如果 JVM 已经在运行:

困难得多。我确实注意到通过 C++ 进行注入的一些事情,这可能会在类加载时为使用ASM生成/修改运行时类提供可能性。这需要将 ASM 作为依赖项包含在内,而大多数项目都没有。使用这种方法,该类是否是最终的都没有关系。从那里,攻击者可以修改该isPasswordValid()方法以始终返回 true。

如果该类已经加载,我认为这是不可能的。在这里查看更多:

C++ 在正在运行的 JVM 中调用函数

调用 API

我想在运行时更改已经加载的 java 类。这该怎么做?

这也提供了一个有趣的阅读:

Java中可以进行代码注入吗?


如果代码被用作库:

容易得多。攻击者可以final像你说的那样删除修饰符,或者使用 ASM 之类的东西生成一个新类,该类首先没有final修饰符。也可以只使用sun.misc.Unsafe,如这里 repo所示。这将允许他们生成一个扩展不再是最终类的新类。

另一种方法是只使用 ASM 在加载类时对其进行修改,这样会更容易。

可能有更多的方法可以做到这一点,我自己还没有实际测试过这些方法,但我认为这两种情况都有可能,具体取决于环境。

编辑:我忘了提到这些东西中的一些可能不适用于更高版本的 Java,其中类操作和依赖访问受到更多限制。我将所有这些都建立在您使用 Java 8 的基础上,大多数人仍然在使用 Java 8。

编辑2: 我刚刚在这里找到了这篇文章,它提供了一种通过调试模式执行任意代码的方法,也可以用来操作类。关联


推荐阅读