Java中的RASP机制实现详解

 更新时间:2019年08月29日 10:37:57   作者:Solinx  
这篇文章主要介绍了Java中的RASP实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

RSAP

RASP是Gartner公司提出的一个概念,称:程序不应该依赖于外部组件进行运行时保护,而应该自身拥有运行时环境保护机制;

RASP就是运行时应用自我保护(Runtime application self-protection)的缩写,正如RASP字面意思一样,这是运行在运行时的一种防护技能;也就是说RASP能够在程序运行期间实施自我保护,监控与过滤有害信息,还能够拥结合程序的当前上下文实施精确、实时的防护;

Java中的RASP

不严格来说Java是半编译、半解释型语言,我们也都知道Java中也有运行时(Runtime)那Java的运行时在哪呢?

不急,我们先看看Java从编译到运行的流程图;

上图的流程为:Java编译程序如Javac编译.java源码文件,生成Java字节码文件.class,接着.class文件进入JVM中解释执行; 从中我们可以看到Java的最后执行阶段是在JVM中,也就可以说Runtime运行时是JVM的重要组成部分;除此之外我们还发现

Java中实现RASP的几个关键点:

1、 我们的防护程序必须能够分析、修改java的.class文件;

2、 必须在JVM解释执行.class文件时进行注入(Java Runtime);

通过上面的分析我们知道了要实现Java的RASP所要具备的能力,然后我们发现在Java中有Javassist、与ASM可以实现对Java字节码的修改;有了修改.class字节码文件的技能,还需要能够在Java运行期间注入我们的防护程序,通过上面我们发现Java运行时是发生在JVM中,通过查找相关资料与JVM参数发现在JVM参数中有-javaagent参数配置Java代理可以在 运行时注入我们的防护程序;

Java RASP实现

在上面的分析中我们发现只要在JVM的-javaagent参数 中配置我们的保护程序,就能够轻松实现Java的RASP;

Java代理程序入口类需要有名为premain的静态方法 ,还需要在jar的META-INF/MAINIFEST.MF文件中包含 Premain-Class配置,下面是RASP保护程序的入口类;

JavaRASPApp:

/**
 * @author linx
 * @date 2017-06-25
*/
public class JavaRASPApp {

 public static void premain(String agentArgs, Instrumentation instru) throws ClassNotFoundException, UnmodifiableClassException {
  System.out.println("premain");
  instru.addTransformer(new ClassTransformer());
 }
}

ClassTransformer类实现了Java的代理程序机制提供的ClassFileTransformer接口 ,能够在运行时(Runtime)对类的字节码进行替换与修改;

ClassTransformer也很简单,只有一个实现方法:transform,此方法中可以获取得到ClassLoader、className、classfileBuffer等,分别为类加载器、类名、字节码 ;

此时我们可以在transform方法中做文章,实现我们的防护程序;

/**
 * @author linxin
 * @version v1.0
 *     Copyright (c) 2017 by linx
 * @date 2017/6/23.
*/
 public class ClassTransformer implements ClassFileTransformer {
 public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer){
  byte[] transformeredByteCode = classfileBuffer;
  try {

    if (className.equals("co/solinx/demo/Test")) {
      System.out.println(String.format("transform start %s",className));
      ClassReader reader = new ClassReader(classfileBuffer);
      ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      ClassVisitor classVisitor = (ClassVisitor) createVisitorIns("co.solinx.demo.visitor.TestVisitor", writer, className);
      reader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
      transformeredByteCode = writer.toByteArray(); 
    }
  } catch (Exception e) {
    e.printStackTrace();
  }catch (Throwable t){
    t.printStackTrace();
  }
  return transformeredByteCode;
}
 public Object createVisitorIns(final String name, ClassVisitor cv, String className)
    throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
  Constructor<?> ctor = Class.forName(name).getDeclaredConstructor(new Class[]{ClassVisitor.class, String.class});
  ctor.setAccessible(true);
  return ctor.newInstance(new Object[]{cv, className});
 }
}

可以看到我们在transform方法中co/solinx/demo/Test类进行拦截,并通过ASM修改字节码注入我们的保护逻辑,下面代码是TestVisitorAdapter类中的onMethodEnter方法实现了通过ASM调用拦截器,抛出异常的字节码;

@Override
protected void onMethodEnter() { 
  mv.visitTypeInsn(NEW,"co/solinx/demo/filter/SqlFilter");
  mv.visitInsn(DUP);
  mv.visitMethodInsn(INVOKESPECIAL,"co/solinx/demo/filter/SqlFilter","<init>","()V",false);
  mv.visitVarInsn(ASTORE,2);
  mv.visitVarInsn(ALOAD,2);
  mv.visitVarInsn(ALOAD,1);
  mv.visitMethodInsn(INVOKEVIRTUAL,"co/solinx/demo/filter/SqlFilter", "filter","(Ljava/lang/Object;)Z",false);
  Label label = new Label();
  /**
   * IFEQ filter返回值也就是栈顶int型数值等于true时跳转,抛出异常
   */
  mv.visitJumpInsn(IFEQ, label); 
  mv.visitTypeInsn(NEW, "java/sql/SQLException");
  mv.visitInsn(DUP);
  mv.visitLdcInsn("invalid sql because of security check");
  mv.visitMethodInsn(INVOKESPECIAL, "java/sql/SQLException", "<init>", "(Ljava/lang/String;)V", false);
  mv.visitInsn(ATHROW);
  mv.visitLabel(label);
  /**
   * 必须要调该方法,手动设置Stack Map Table,否则会有 java.lang.VerifyError: Expecting a stackmap frame at branch target 26异常
   * 在jdk1.7中可以使用JVM参数-UseSplitVerifier,关掉class验证,但jdk1.8中该参数已经去掉,所以要在1.8中运行必须调用该方法;
   */
  mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
 } 

SqlFilter拦截类:

public class SqlFilter {
public boolean filter(Object sql){
  boolean ret=false;
  System.out.println(String.format("sql filter : %s ",sql));
  if(sql.toString().contains("1=1")){
    ret=true;
  }
  return ret;
}
}

TestVisitorAdapter类中的onMethodEnter方法中通过调用filter拦截器,返回true就是被拦截了,抛出异常,否则放行;至此一个简单的JAVA RASP demo就完成了; 通过后面的方式即可使用我们的RASP程序:java -javaagent:respjar-1.0-SNAPSHOT.jar app.jar;

通过RASP可以通过无嵌入、无需修改代码的实现安全保护,在RASP中可以拦截SQL、会话、有害请求、OGNL等等信息;

Demo源码:https://github.com/linxin26/javarespdemo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Springboot 全局时间格式化三种方式示例详解

    Springboot 全局时间格式化三种方式示例详解

    时间格式化在项目中使用频率是非常高的,当我们的 API​ 接口返回结果,需要对其中某一个 date​ 字段属性进行特殊的格式化处理,通常会用到 SimpleDateFormat​ 工具处理,这篇文章主要介绍了3 种 Springboot 全局时间格式化方式,需要的朋友可以参考下
    2024-01-01
  • java -jar设置添加启动参数实现方法

    java -jar设置添加启动参数实现方法

    这篇文章主要介绍了java -jar设置添加启动参数实现方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java并发编程中的ConcurrentLinkedQueue详解

    Java并发编程中的ConcurrentLinkedQueue详解

    这篇文章主要介绍了Java并发编程中的ConcurrentLinkedQueue详解,GetThread线程不会因为ConcurrentLinkedQueue队列为空而等待,而是直接返回null,所以当实现队列不空时,等待时,则需要用户自己实现等待逻辑,需要的朋友可以参考下
    2023-12-12
  • 改善Java代码之慎用java动态编译

    改善Java代码之慎用java动态编译

    这篇文章主要介绍了改善Java代码之慎用java动态编译,需要的朋友可以参考下
    2021-04-04
  • SpringBoot项目Jar包如何瘦身部署的实现

    SpringBoot项目Jar包如何瘦身部署的实现

    这篇文章主要介绍了SpringBoot项目Jar包如何瘦身部署的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java中String的JdbcTemplate连接SQLServer数据库的方法

    Java中String的JdbcTemplate连接SQLServer数据库的方法

    这篇文章主要介绍了Java中String的JdbcTemplate连接SQLServer数据库的方法,在研发过程中我们需要与其他系统对接的场景,连接SQLServer拉取数据,所以就用jdbc连接数据库的方式连接外部数据源,需要的朋友可以参考下
    2021-10-10
  • Intellij Mybatis连接Mysql数据库

    Intellij Mybatis连接Mysql数据库

    最近在搞android的项目,在开发过程中遇到了好多问题,今天小编给大家说下mybatis连接MySQL数据库的方法,感兴趣的朋友跟着小编一起学习吧
    2016-10-10
  • 如何通过Java代码实现KMP算法

    如何通过Java代码实现KMP算法

    这篇文章主要介绍了如何通过Java代码实现KMP算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 一分钟了解Java中List集合与set集合的多种遍历方式

    一分钟了解Java中List集合与set集合的多种遍历方式

    这篇文章主要介绍了一分钟了解Java中List集合与set集合的多种遍历方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 用Java进行zip文件压缩与解压缩

    用Java进行zip文件压缩与解压缩

    这篇文章主要介绍了用Java进行zip文件压缩与解压缩的方法,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-12-12

最新评论