【问题标题】:Class based impersonation基于类的模拟
【发布时间】:2011-05-25 08:22:08
【问题描述】:

一个类可以冒充它的身份吗?例如,A 类尝试访问B 类方法。 B 类方法使用getClass().getName() 尝试检查A 类以确保它是谁。可以冒充吗?例如C 类模拟 A 类以通过 getclass().getName()B 用于检查?

如果 Class B 想要实现 getClass().getName() 对下面的示例方法有效的检查,我如何在下面的示例代码中正确实现它?

public byte[] getStoragePrivateKey(String application) {
    if (application.getClass().getName().equals("correctClass") {
        // Allow access to Private Key.
    } else {
        // Access denied
    }
}

上面的例子是模拟系统中的一个插件小程序试图访问系统中的内部密钥服务器数据库。

【问题讨论】:

标签: java class impersonation


【解决方案1】:

您可以使用多个类加载器来执行此操作。每个class laoder可以有一个不同的同名类。

但是,如果可以绕过此“安全性”,我建议您只使用反射

编写验证的更简单方法是

if (application.getClass() == CorrectClass.class) {

实现验证的一种改进方法是使用

StackTraceElement[] stes = Thread.currentThread().getStackTrace();
if (stes[0].getClassName().equals("correctClass") {

这确保调用者来自正确的类名。它仍然可以被类加载器欺骗。

sun.misc.Unsafe 类使用类似后者的东西来保护 getUnsafe() 方法。标准的解决方法是做。

Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unafe = theUnsafe.get(null);

如果您想知道为什么 Unsafe 受到保护以及您可能想要访问的原因,请查看方法列表。 ;)

编辑: Unsafe.getUnsafe() 曾经受到保护,但在最新源中似乎不再受到保护。可能是因为检查很容易被绕过。 ??

【讨论】:

  • 虽然你不能加载假的 java.* 类,或者通常是由父类加载器加载的任何类。
  • @Tom Hawtin,并非没有违反许可协议。但这在技术上是可行的。我已经写过关于使用自压缩字符串的文章,一个报告在哪里调用 gc() 的运行时等。Terracotta 在运行时更改了 java.* 类,Profiler 将代码注入任何类以获取更多信息。但是,我不相信他们会加载多个副本。
  • @Peter Lawrey 你可以用-Xbootclasspath 或类似的东西替换部分Java库,但你不应该使用类加载器来实现它。
  • @Tom Hawtin,我怀疑你是对的,但我知道你可以通过 Instrumentation 做到这一点。
  • @Peter Lawrey Java 代理与使用-Xbootclasspath 大致相同。
【解决方案2】:

这不起作用: 在您的示例中,application.getClass().getName() 将始终返回 "java.lang.String",因为您正在获取“应用程序”参数的类型。

此外,在 Java 中,被调用的方法无法找出它被调用的类型,所以也许,你应该检查你的设计,实现一些其他类型的访问控制。

编辑:让我根据您的代码添加一个示例,说明您如何尝试检查调用程序的类型,以及它如何避免来自其他来源的调用:

//Change the String for an Object, to allow the invoker pass a 
//reference to itself
public byte[] getStoragePrivateKey(Object application) {
    if (application.getClass().getName().equals("correctClass") {
        // Allow access to Private Key.
    } else {
        // Access denied
    }
}

从引用类型 A,调用可能是:

  B b=new B();
  byte[] key=b.getStoragePrivateKey(this);

从 C“模仿者”类调用它会失败,因为这是一个 C.class 实例:

  B b=new B();
  byte[] key=b.getStoragePrivateKey(this);

但是,避免验证很简单:

  B b=new B();
  A a=new A();
  byte[] key=b.getStoragePrivateKey(a); 

【讨论】:

    猜你喜欢
    • 2018-08-12
    • 2013-03-17
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多