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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍详解Java动态代理的实现机制,包括了详解Java动态代理的实现机制的使用技巧和注意事项,需要的朋友参考一下 一、概述 代理是一种设计模式,其目的是为其他对象提供一个代理以控制对某个对象的访问,代理类负责为委托类预处理消息,过滤消息并转发消息以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口。 按照代理的创建时期,代理类可分为两种:
本文向大家介绍详解Spring mvc DispatchServlet 实现机制,包括了详解Spring mvc DispatchServlet 实现机制的使用技巧和注意事项,需要的朋友参考一下 在Spring中, ContextLoaderListener只是辅助类,在web 容器启动的时候查找并创建WebApplicationContext对象,通过该对象进行加载spring的配置文件。而真正
本文向大家介绍Java的回调机制实例详解,包括了Java的回调机制实例详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java的回调机制。分享给大家供大家参考,具体如下: 一 代码 二 运行 I've been called back 三 说明 回调机制的真正意图,就是实现控制反转,通过控制反转。对象在被创建的时候(如A处),由一个能够调控系统内所有对象的外界实体(如B处的caller
本文向大家介绍java 回调机制的实例详解,包括了java 回调机制的实例详解的使用技巧和注意事项,需要的朋友参考一下 java 回调机制的实例详解 序言 最近接触到了回调机制(CallBack)。初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义。当然了,我在理解了回调之后,再去看网上的各种讲解,确实没什么问题。但是,对于初学的我
本文向大家介绍Java 反射机制的实例详解,包括了Java 反射机制的实例详解的使用技巧和注意事项,需要的朋友参考一下 Java 反射机制的实例详解 前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来。那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现。 正文 Java反射机制定义 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类
本文向大家介绍Java中的反射机制详解,包括了Java中的反射机制详解的使用技巧和注意事项,需要的朋友参考一下 Java中的反射机制详解 反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修