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

huangapple go评论79阅读模式
英文:

Is limitation of accessibility for classes and their members a valid practice for more secure code?

问题

根据 Oracle安全编码准则 中的Guideline 4-1/EXTEND-1和Guideline 4-5/EXTEND-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修饰符(如果之前存在的话),或以任何方式修改类本身吗?

英文:

According to Oracle Secure Coding Guideline Guideline 4-1/EXTEND-1 and Guideline 4-5/EXTEND-5
you should limit the accessibility of classes and their members as a security control against malicious override from an attacker.

> 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.

How could an attacker actually exploit the below insecure class in real world scenario?
Could he/she do it even if the class is already loaded in a running 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;
   }
}

If we are talking about a malicious insider who has access to the source code, couldn't he just remove the final modifier(if one was there already) or alter the class itself by any means in the first place?

答案1

得分: 0

代码不安全,无论是否有final关键字。它还极大地取决于它运行的环境。

如果JVM已在运行:

要困难得多。我注意到一些通过C++进行注入的事情,这可能会为诸如在类加载时使用ASM进行运行时类生成/修改之类的事情打开可能性。这将需要将ASM作为依赖项包含在内,而大多数项目不会这样做。使用此方法,类是否为final都无关紧要。从那时起,攻击者只需修改isPasswordValid()方法以始终返回true。

如果类已加载,我认为这是不可能的。在此处查看更多信息:

https://stackoverflow.com/questions/55286883/c-call-a-function-inside-a-running-jvm

调用API

https://stackoverflow.com/questions/43653397/i-want-to-change-java-class-at-run-time-which-is-already-loaded-how-to-do-this

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

https://stackoverflow.com/questions/1880929-is-code-injection-possible-in-java


如果代码被用作库:

要简单得多。攻击者可以像你说的那样删除final修饰符,或者使用类似ASM的工具生成一个一开始就没有final修饰符的新类。也可以使用sun.misc.Unsafe,就像这个存储库中展示的那样这里。这将允许他们生成一个继承不再是final类的新类。

另一种方法是在加载类时使用ASM来修改类,这将更容易。

可能还有更多的方法,我实际上还没有测试过这些方法,但我认为在不同环境下都有可能实现。

编辑: 我忘了提到有些东西在较新版本的Java中可能无效,在那里类操作和依赖项访问受到了更严格的限制。我基于您使用的是Java 8进行所有这些操作,大多数人仍在使用Java 8。

编辑2: 我刚刚找到了这篇文章,其中提供了一种通过调试模式执行任意代码的方法,这可以用于操作类。链接

英文:

That code isn't safe, whether there's a final keyword or not. It also depends wildly on the environment it's running in.

If the JVM is already running:

Much more difficult. I did notice some things with injection through C++, which could open up possibilities to things like runtime class generation/modification with ASM as the class is loading. This would require ASM to be included as a dependency, which most projects won't have. Using this method, it wouldn't matter if the class was final or not. From there, the attacker can just modify the isPasswordValid() method to always return true.

If the class is already loaded, I don't think it's possible. See more here:

https://stackoverflow.com/questions/55286883/c-call-a-function-inside-a-running-jvm

The Invocation API

https://stackoverflow.com/questions/43653397/i-want-to-change-java-class-at-run-time-which-is-already-loaded-how-to-do-this

This also provides an interesting read:

https://stackoverflow.com/questions/1880929/is-code-injection-possible-in-java


If the code is being used as a library:

Much easier. The attacker could either remove the final modifier like you said, or generate a new class with something like ASM that doesn't have the final modifier in the first place. One could also just use sun.misc.Unsafe, as shown in this repo here. This would allow them to generate a new class that extends the no longer final class.

Another method is to just use ASM to modify the class as it's loading, which would be easier.

There are probably more ways of doing it, and I haven't actually tested any of these myself, but I think that it's possible in both situations depending on the environment.

EDIT: I forgot to mention that some of this stuff might not work in later versions of Java, where class manipulation and dependency access is much more restricted. I'm basing all of this off of you using Java 8, which most people still do.

EDIT 2:
I just found this article here which provides a method for executing arbitrary code through debug mode, which can be used to manipulate the class also. Link

huangapple
  • 本文由 发表于 2020年9月21日 03:47:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/63983042.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定