java - 如何防止 Java 代理中定义的 Lambda 表达式破坏其所附加的应用程序?

标签 java byte-buddy javaagents java-security-manager

如果我向我的代理人声明此建议:

public static class SequenceAdvice {
    @Advice.OnMethodEnter
    static void enter(@Advice.This Object thiz, 
                      @Advice.Origin Method method, 
                      @Advice.AllArguments Object... args) {
        StackWalker walker = 
            StackWalker.getInstance(RETAIN_CLASS_REFERENCE);

        walker.forEach(sf -> 
            System.out.println(sf.getClassName() + "." + sf.getMethodName())
        );
    }
}

as javac 将 lambda 表达式编译为私有(private)方法(至少在 OpenJDK 11 中):

public class SequenceAgent$SequenceAdvice {
  ...
  private static void lambda$enter$0(java.lang.StackWalker$StackFrame);
  ...
}

当代理附加到程序并执行该程序时,会导致程序崩溃:

Exception in thread "main" java.lang.IllegalAccessError: 
  class DemoController tried to access private method
    SequenceAgent$SequenceAdvice.lambda$enter$0(
       Ljava/lang/StackWalker$StackFrame;)V 
         (DemoController and SequenceAgent$SequenceAdvice 
          are in unnamed module of loader 'app')
    at DemoController.getDemos(DemoController.java)
    at DemoMain.main(DemoMain.java:13)

理想情况下,我不喜欢使用对象而不是 lambda 表达式来解决此问题:

public static class SequenceAdvice {

    public static Consumer<StackWalker.StackFrame> SF_CONSUMER = 
        new Consumer<>() {
            @Override
            public void accept(StackWalker.StackFrame sf) {
                System.out.println(sf.getClassName() + "." + sf.getMethodName());
            }
    };

    @Advice.OnMethodEnter
    static void enter(@Advice.This Object thiz, 
                      @Advice.Origin Method method, 
                      @Advice.AllArguments Object... args) {
        StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);

        walker.forEach(SF_CONSUMER);
    }
}

自定义的宽松安全策略似乎无法解决此错误:

grant {
    permission java.security.AllPermission;
};

有没有办法暂时禁用此类安全检查(例如“访问私有(private)方法”)?

最佳答案

您不能使用建议中的 lambda 表达式。 lambda 表达式将是建议类的一部分,不会暴露给目标类。相反,您需要定义一个实用程序类,该类在公共(public)方法中定义 lambda 表达式代码,并将这些方法作为方法引用进行引用。

然后您必须:

  1. 通过 Instrumentation 将此类添加到引导类加载器。
  2. 通过 Byte Buddy 的 Injector 将此类添加到检测类的类加载器中。

这样,引用就可供检测的类使用并且可以执行。

关于java - 如何防止 Java 代理中定义的 Lambda 表达式破坏其所附加的应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56413823/

相关文章:

java - 如何使用 ByteBuddy 添加自定义获取/设置方法

java - Arraylist通过setter添加对象

java - 如何验证构造函数中私有(private)方法调用的次数?

java - 从默认 http 客户端设置的 openfeign 请求中删除 header

java - 如何使用用户选择的构造函数创建实例?

java - 显示生成的 bytebuddy 字节码

java - 如何拦截构造函数

java - Java 代理是否在单独的线程中运行?

java - 使用 -javaagent 不将 agent 打包到 jar 中

macos - "Error opening zip file or JAR manifest missing"在 IntelliJ 中配置 javaagent 时