velocity的标签中支持$abc 这样的语法,如果abc是一个对象,则写模板时就可以利用它来进行反射,调用一些危险的方法,如

$vm.getClass().newInstance()
#set ($exec = "kxlzx")$exec.class.forName("java.lang.Runtime").getRuntime().exec("calc")

  

通过反射,让系统本身出现了安全漏洞,这类危险的操作,可以通过屏蔽反射来杜绝,在velocity属性中添加一行配置即可

runtime.introspector.uberspect = org.apache.velocity.util.introspection.SecureUberspector

  

velocity默认的配置为:

runtime.introspector.uberspect = org.apache.velocity.util.introspection.UberspectImpl

  

本文主要讨论从velocity初始化过程到解析标签。以及如何通过

SecureUberspector

  

来屏蔽反射,欢迎补充。

velocity的内省主要的用处是解析如$a.id,$a.name的引用,与其说是内省,不如说是通过反射找get方法。。。。

关于内省的概念 传送门:http://www.cnblogs.com/peida/archive/2013/06/03/3090842.html

先来分析velocity的初始化过程

这里只是对velocity初始化过程的概括,初始化过程大量依赖的配置参数,即velocity.properties,用户一般自定义该文件或直接载入Properties,默认的配置目录为

org/apache/velocity/runtime/defaults/velocity.properties

  

调用方法渲染流程

VelocityEngine velocityEngine = new VelocityEngine("/velocity.properties");
velocityEngine.evaluate(context, writer, "logMsgName", new InputStreamReader(VelocityTest2.class.getResource("test.vm").openStream()));

  

生成NodeTree的代码比较复杂,可能用的是某种算法,总之,最后的Tree里面包含了所有的vm信息,如果是parse\include会生成AsTDirective,如果是文本,会生成ASTText对应,如果是set,会生成ASTSetDirective,如果是引用,会生成ASTReference对应。。等等。。

这里列举几个标签的处理流程

parse

从源代码分析来看,parse标签里面的内容甚至可以写成动态的,如

#parse("${a}.vm")

  

发送includeEvent和velocity初始化过程中的各个事件处理器是对应的,引入vm文件外的文件,都会触发includeEvent,然后根据其返回值,来找到真正的vm资源文件,因此,我们可以在eventHander中重定向返回的资源位置,如 a.vm -> b.vm

另外,parse和include 对velocity来说,是两种type,解析parse文件时,会把context传入进行解析

引用标签,如$a,$vm.id

普通的引用渲染流程不包括子流程 “SecureUberspector拦截方法”,如果引用值为$a.id ,则会去找a.getid() -> a.getId(),,然后反射调用method.invoke(objecct)

引用的渲染流程会根据identifier和method进行不同的流程

identifier方式即$a.id

method方式即$a.println()

为什么下面两行嗲吗的效果一样呢

$exec.class
$exec.getClass()

  

原因就在这里,velocity把class当成一个属性来处理了,因此,去找getClass方法,恰好对象都有getClass方法,这样效果就和直接写$exec.getClass()一样了

SecureUberspector如果达到屏蔽反射方法的呢,先来看一看它的类依赖

UberspecttImpl中有一个introspector对象,SecureUberspector对其进行了重定义SecureUberspector的初始化方法如下,badPackages和badClass的配置也是在默认的velocity.properties中配置的,用户可以添加更多的配置

public void init()
{
String [] badPackages = runtimeServices.getConfiguration()
.getStringArray(RuntimeConstants.INTROSPECTOR_RESTRICT_PACKAGES); String [] badClasses = runtimeServices.getConfiguration()
.getStringArray(RuntimeConstants.INTROSPECTOR_RESTRICT_CLASSES); introspector = new SecureIntrospectorImpl(badClasses, badPackages, log);
}

  

SecureIntrospectorImpl实现了方法

public Method getMethod(Class clazz, String methodName, Object[] params)
throws IllegalArgumentException
{
if (!checkObjectExecutePermission(clazz, methodName))
{
log.warn("Cannot retrieve method " + methodName +
" from object of class " + clazz.getName() +
" due to security restrictions.");
return null;
}
else
{
return super.getMethod(clazz, methodName, params);
}
}
/**
* Determine which methods and classes to prevent from executing. Always blocks
* methods wait() and notify(). Always allows methods on Number, Boolean, and String.
* Prohibits method calls on classes related to reflection and system operations.
* For the complete list, see the properties <code>introspector.restrict.classes</code>
* and <code>introspector.restrict.packages</code>.
*
* @param clazz Class on which method will be called
* @param methodName Name of method to be called
* @see org.apache.velocity.util.introspection.SecureIntrospectorControl#checkObjectExecutePermission(java.lang.Class, java.lang.String)
*/
public boolean checkObjectExecutePermission(Class clazz, String methodName)
{
/**
* check for wait and notify
*/
if (methodName != null &&
(methodName.equals("wait") || methodName.equals("notify")) )
{
return false;
} /**
* Always allow the most common classes - Number, Boolean and String
*/
else if (Number.class.isAssignableFrom(clazz))
{
return true;
}
else if (Boolean.class.isAssignableFrom(clazz))
{
return true;
}
else if (String.class.isAssignableFrom(clazz))
{
return true;
} /**
* Always allow Class.getName()
*/
else if (Class.class.isAssignableFrom(clazz) &&
(methodName != null) && methodName.equals("getName"))
{
return true;
} /**
* check the classname (minus any array info)
* whether it matches disallowed classes or packages
*/
String className = clazz.getName();
if (className.startsWith("[L") && className.endsWith(";"))
{
className = className.substring(2, className.length() - 1);
} int dotPos = className.lastIndexOf('.');
String packageName = (dotPos == -1) ? "" : className.substring(0, dotPos); for (int i = 0, size = badPackages.length; i < size; i++)
{
if (packageName.equals(badPackages[i]))
{
return false;
}
} for (int i = 0, size = badClasses.length; i < size; i++)
{
if (className.equals(badClasses[i]))
{
return false;
}
} return true;
}

  

SecureIntrospectorImpl

这里可以看见它对对象访问方法的屏蔽操作

badPackage:java.lang.refect

badClass:

那么,为什么我们不直接使用SecureIntrospectorImpl呢,因为它仅仅是一个工具

SecureUberspector类对foreach标签也进行了支持

/**
* Get an iterator from the given object. Since the superclass method
* this secure version checks for execute permission.
*
* @param obj object to iterate over
* @param i line, column, template info
* @return Iterator for object
* @throws Exception
*/
public Iterator getIterator(Object obj, Info i)
throws Exception
{
if (obj != null)
{
SecureIntrospectorControl sic = (SecureIntrospectorControl)introspector;
if (sic.checkObjectExecutePermission(obj.getClass(), null))
{
return super.getIterator(obj, i);
}
else
{
log.warn("Cannot retrieve iterator from " + obj.getClass() +
" due to security restrictions.");
}
}
return null;
}

  

就这样,foreach时,如果对象是java.lang.refect包下的类或badClass,就没有权限了

velocity 是如何实现内省 屏蔽反射的的更多相关文章

  1. Introspector内省和反射的区别.

    Introspector 是一个专门处理bean的工具类.用来获取Bean体系里的 propertiesDescriptor,methodDescriptor. 要理解这个,就要理解下面几个议题.   ...

  2. Java 基础【18】 反射与内省

    1.概念定义 Java 反射机制(Reflect)容许程序在运行时加载.探知.使用编译期间完全未知的 class,核心类 java.lang.Class. 通过把指定类中各种元素映射成 java.la ...

  3. 理解Java的反射与内省及其区别

    java的内省机制和反射机制什么区别 内省操作只针对JavaBean,只有符合JavaBean规则的类的成员才可以采用内省API进行操作....而反射则不同,一个类的所有成员都可以进行反射操作. 内省 ...

  4. java 深入技术八(内省)

    1. javabean的软件设计思想 2.内省:封装了java反射,提供直接操作属性的Setter和getter方法的方法 3.核心API:BeanInfo java 的描述信息,Introspect ...

  5. java内省机制及PropertyUtils使用方法

    背景 一般情况下,在Java中你可以通过get方法轻松获取beans中的属性值.但是,当你事先不知道beans的类型或者将要访问或修改的属性名时,该怎么办?Java语言中提供了一些像java.bean ...

  6. 【转】Velocity模板(VM)语言介绍

    http://www.blogjava.net/caizh2009/archive/2010/08/20/329495.html Velocity是什么? Velocity是一个基于java的模板引擎 ...

  7. javaweb学习总结五(内省、beanUtils工具包)

    一:内省的概念 1:内省是反射的一种特例,由于在反射中频繁的操作javabean,所以为了方便反射 javabean,sun公司开发出一套API提高效率. 2:javaBean,就是用来封装客户端请求 ...

  8. 转:Java反射教程

    原文来自于:http://www.importnew.com/9078.html 什么是反射?反射有什么用处? 1. 什么是反射? “反射(Reflection)能够让运行于JVM中的程序检测和修改运 ...

  9. Javaweb学习笔记——(十二)——————JSP指令:page指令、include指令、taglib指令,JavaBean,内省,EL表达式

    JSP指令JSP指令分类 JSP有三大指令: *page指令 *include指令 *taglib指令 在JSP中没有任何指令是必须的. 但基本上每个JSP都是使用page指令============ ...

随机推荐

  1. Machine-learning of Andrew Ng(Stanford University)

    1.基础概念 机器学习是一门研究在非特定编程条件下让计算机采取行动的学科.最近二十年,机器学习为我们带来了自动驾驶汽车.实用的语音识别.高效的网络搜索,让我们对人类基因的解读能力大大提高.当今机器学习 ...

  2. Vue源码后记-vFor列表渲染(1)

    钩子函数比较简单,没有什么意思,这一节搞点大事情 => 源码中v-for的渲染过程. vue的内置指令包含了v-html.v-if.v-once.v-bind.v-on.v-show等,先从一个 ...

  3. 使用gitbook

    前面的话 gitbook功能强大,可以自动实现搜索及翻页等功能,上手容易,用markdown书写即可,且可以自动生成响应式网站.本文将详细介绍如何使用gitbook 安装 1.使用npm全局安装git ...

  4. runtime--小白看过来

    目录 RunTime 概述 RunTime消息机制 RunTime交换方法 RunTime消息转发 RunTime关联对象 RunTime实现字典与模型互转 1.RunTime 概述 我们在面试的时候 ...

  5. 1053: [HAOI2007]反素数ant

    1053: [HAOI2007]反素数ant Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3480  Solved: 2036[Submit][St ...

  6. 2016年中国大学生程序设计竞赛(杭州)1006 Four Operations

    Four Operations Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  7. 利用 pandas 进行数据的预处理——离散数据哑编码、连续数据标准化

    数据的标准化 数据标准化就是将不同取值范围的数据,在保留各自数据相对大小顺序不变的情况下,整体映射到一个固定的区间中.根据具体的实现方法不同,有的时候会映射到 [ 0 ,1 ],有时映射到 0 附近的 ...

  8. spring boot + thymeleaf 3 国际化

    在给spring boot 1.5.6 + thymeleaf 3进行国际化时,踩了一个坑(其实不止一个). 现象: 看到了吧, 就是取值的key, 后面被加了_en_US 或 _zh_CN, 以及前 ...

  9. 编程语言 : Java的动态Web解决方案泛谈

    文章概述 最近发现很久前一股脑地学习框架,发觉越发迷糊.知道了框架只是暂时的,重点是基础的技术.该文大篇幅回顾Servlet技术栈和简要的MVC框架. 至于为什么学J2EE,额,大家都用框架,可框架也 ...

  10. Less循环

    Less循环 在Less中,mixin可以调用它自身.通过这种递归调用,再结合Guard表达式和模式匹配,就可以写出各种循环结构.如,使用循环来创建一个网格类: .generate-columns(4 ...