您的位置:首页 > 编程语言 > Java开发

Java Struts 特性和新特性总结

2015-11-17 15:03 330 查看

struts2新特性预览

Struts2与Struts1的对比 

Action 类: 

• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 

• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。 

线程模式: 

• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 

• Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题) 

Servlet 依赖: 

• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 

• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。 

可测性: 

• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 

• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。 

捕获输入: 

• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。 

• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven 特性简化了taglib对POJO输入对象的引用。 

表达式语言: 

• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 

• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).  

绑定值到页面(view): 

• Struts 1使用标准JSP机制把对象绑定到页面中来访问。 

• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。 

  

类型转换: 

• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 

• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 

校验:  

• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 

• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性  

Action执行的控制: 

• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 

• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

Struts2 优点收集整理

Struts2比Struts1已经有了很大的进步,优点很多,其中主要是: 

增强页面数据处理功能(OGNL、valueStack)。

简化捕获表单数据对象过程 (类型转换)

提供灵活丰富功能和插件, 易于使用和扩展 (拦截器、插件支持、Action生命周期、校检);

提高线程安全性(单例—原型);

提高可测性(不依赖servlet、struts,提供依赖注入);

表达式语言:

• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 

• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL). 

【((EntCustomer)jack.getCustomer()).getTrustId()----jack.customer.trustId】 

** 不需关注对象类型,不需进行类型转换 

** 表达方式更简短和直观 

绑定值到页面(view):

• Struts 1使用标准JSP机制把对象绑定到页面中来访问。 

• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。 

插件支持:

• Struts2是基于插件开发的框架,能简单快速的使用大量成熟实用的插件和视图 

依赖注入:

• Struts2提供依赖注入,并能很好的和spring ioc整合。 

Struts2 AOP-拦截器:

• Struts2提供强大的、可插拔的拦截器以及拦截器栈, 

个人觉得Struts1是基于servlet开发,Struts2是基于Filter开发,相对于现在的企业来说Struts1的技术成熟,便于维护,而且现在的许多程序员使用SSH框架时,还是多选用struts1来开发~~ 当然Struts2安全性比Struts1要高~~ 

Action生命周期控制:

• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 

• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。 

线程安全:

• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 

• Struts2 Actions是原型模式,对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题) 

Struts框架依赖:

• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 

• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。 

Servlet 依赖:

• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 

• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。 

捕获输入[表单数据封装对象:]:

• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。 

• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。 

可测性:

• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 

• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。 

类型转换:

• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 

• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。 

校验:

• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 

• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性

Struts2的新特性new

Struts 1.0非常成熟,因此得到众多开发社区的有力支持,而且说明文档内容完备。不过在过去的几年里,许多开源社区的Web框架纷纷登台亮相,所以它需要跟上 Web应用需求不断变化的形势,这就有必要构建下一代Struts框架。力求满足这个要求的初始提案是Struts Ti,这种简化的MVC Model 2框架可用于让需要更少配置、更好结构和控制器特性的人开发Web应用。

WebWork项目由Open Symphony社区启动,面向Struts开发社区。它旨在满足那些希望寻求类似Struts的一种框架,但有更好特性的人的需要。WebWork框架 于2002年发布。独立运作了几年后, WebWork和Struts两个社区在2005年12月联合起来,开发了新版本的Struts,即Struts 2。Struts 2实际上就是Struts 1与WebWork的结合体。Struts的这个新版本更易使用,更接近Struts框架的最初版本。

Struts 2.0的新特性

改进的设计: 与Struts 1相比,Struts 2的所有类都基于接口,核心接口独立于HTTP。这些API并不依赖服务器小程序API。

简化的Action: Struts 2 Action类独立于框架,是简化的普通Java对象(POJO)。拥有execute()方法的任何Java类都可以用做Action类。

POJO表单: Struts 2不支持ActionForms特性。ActionForms中定义的属性可以直接放在Action类上。不需要使用所有的String属性。

智能默认值: Struts 2配置文件中的大多数配置元素都会有默认值,所以不需要设定值,除非需要不同的值。这有助于减少在XML文件中需要进行的配置。Struts 2支持注释,这带来了更大的方便。

改进的结果: 在Struts 2中,

>forward<标签被<result>标签取代。不像 ActionForwards,Struts 2结果可以帮助准备响应,并提供构建多种输出类型的灵活性。

改进的标签: Struts 2标签不单单发送输出数据,还能提供样式表驱动标记,这样就可以用较少的代码构建一致性页面。Struts 2标签现在可与FreeMarker、Velocity及类似模板引擎配合使用。

引入拦截器: Struts 2为拦截器(interceptor)提供了全面支持。拦截器可在Action类执行前后加以执行。拦截器经配置后,可以把工作流程或者验证等常见功能作 用到请求上。所有请求通过一组拦截器传送,之后再发送到Action类。Action类被执行后,请求按照相反顺序再次通过拦截器传送。

支持Ajax: 为了创建使用Ajax的动态Web应用,Struts 2提供了Ajax主题,从而大大改进了交互应用。面向Ajax的Struts 2标签基于Dojo窗口组件。还有用于其他框架的插件。

快速启动: 部署配置文件可以重新装入; 因而,可以动态地进行许多变化,用不着重新启动Web容器。

状态复选框: Struts 2框架可自动跟踪复选框,如果缺少了某复选框,就会采用默认值false。因而,不像在Struts 1中,复选框不需要对false值进行特殊处理。

易于测试: Struts 2 Actions独立于HTTP,因而与框架中立。无须使用模拟对象(mock object),就很容易测试。

使用注释: 使用Struts 2开发的应用可以使用Java 5注释,作为XML和Java属性配置之外的一个替代办法。注释尽量减少了对XML的需要。Action、拦截器、验证及类型转换方面都有注释。

易于插入: 只要把插件JAR文件放到\WEB-INF\lib目录中,即可轻松安装Struts 2插件,不需要手动配置。

便于与Spring集成: Struts 2 Action能够感知Spring(Spring-aware)。只要为某个应用添加Spring beans,就可以添加对Spring的支持。

易于定制的控制器: Struts 1允许请求处理程序可按照模块来定制,在Struts 2中,需要的话,可以按照动作来定制请求处理。

Struts框架开发安全特性

此文是我前年研究struts框架相关安全特性做的总结,这里发上来,各位安全工作人员在查找Struts相关应用的漏洞有一定用处,但因为是去年的文档,因此可能有一些过时内容,大家在参考时需要注意。

前言 

Struts是目前J2ee Web开发中最常见使用的MVC框架。由于使用框架编写的应用程序与原生jsp编写的Web程序区别较大,因此有必要专门撰写一篇文档描述Struts框架的安全特性,及其检查方法。 

Struts介绍 

Struts是一套MVC框架,目前分为两个大版本号。1.x系列,已经放弃开发,是一个较为简单的框架,安全特性也较少。2.x系列则是直接与webwork这个框架合并之后基于webwork重新开发的一套全新框架。目前主流使用框架基本就是2.x系列。 

Struts1 

s1.png 

图 2.1 struts1架构图 

如上图所示,struts 1.x系列的模型主要分为几个部分:最主要的Dispatcher、Controller是使用J2ee的servlet实现的,用户请求过来,通过用户自定义的一系列过滤器(filter)之后,servlet分析匹配其url结构,再转给各action类,最后进行form的填充控制、View层的调用展现。其主要代码是在action中实现的,可以根据struts-config.xml中的配置,根据url->action->view的对应关系一一查看其代码。Struts1中的统一控制一般做在filter中,或者由form的校验函数做数据有效性控制。 

Struts2 

s2.png 

图 2.2 struts2架构图 

而struts2.x的架构就复杂很多,也细致的多。用户的请求过来,先经过一系列过滤器(Filter实现),最后一个过滤器通过actionProxy才是真正对不同的action派发调用,其中的派发规则由struts.xml定义。这几部分相加,才类似于之前Struts1中的ActionServlet的作用。在调用action之前,还有类似Hook的机制,在action执行前后、view执行前后分别有可以统一执行的用户自定义代码。在struts2的说法中,叫做拦截器(Interceptor)。通常struts2中的统一控制就在过滤器、拦截器、校验器这几个方面做控制,其中后两者最普遍。 

如何区分Struts框架应用程序 

URL中以.do结尾的,struts1框架;以.action结尾的,struts2框架。 

Struts1由于是通过servlet进行的action控制,因此主要配置文件在WEB-INF/web.xml及struts-config.xml这两个文件中;Struts2的配置文件则主要就是WEB-INF/struts.xml。 

目录组织结构中如果有Filter、Interceptor的定义实现,通常是Struts2的代码。 

如果有专门的xxxForm.java代码,一般是Struts1的项目;Struts2通常只有一些简单的Java Bean定义作为模型。 

Struts框架安全特性 

Struts1的白盒安全测试方法 

之前我们说过,Struts1中的统一控制一般做在filter中,或者由form的校验函数做数据有效性控制。因此,无论是哪一方面的统一控制,例如参数的统一过滤、验证是否登录、文件上传验证之类,通常是在Filter中进行的;而参数的有效性,例如email只允许[0-9a-zA-Z_@]。 

建议在读代码时,先通读web.xml和struts-config.xml两个文件,从web.xml中了解filter的设置,将所有filter通读一遍,了解总体上做了什么限制,再从struts-config.xml了解action与actionForm、View的对应关系,然后根据这些关系,检查form中的参数有效性验证方法(validate函数)是否做了足够的检查,以及view中是否有基本的html过滤。具体测试case这里不多言,只要找对地方,java的测试case和其他语言也基本都差不多。 

Struts1安全特性 

参数获取 

通常使用J2ee中最常见的Request.getParamter()方法获取用户输入。此方法结合了GET/POST中提交的变量,如果两者有重名,则GET获取的优先,获取的内容非常原始,没有任何改变。不同于PHP中的$_REQUEST变量,Request.getParamter方法并没有包含cookie中获取的变量。 

actionForm中获取的变量也是框架通过上述方法获取的,因此虽然看起来是直接使用没有通过函数获取,实际上也是一样。 

文件操作 

文件下载在struts中并没有做任何限制。在文件上传中,一般是使用Apache-Common-FileUpload的组件。其中也未替代用户做任何限制和检查,需要手工实现扩展名判断、验证等代码。因此如果action中的逻辑代码没有做任何检查,基本可以判断存在问题。 

前端防范 

一般Struts1使用jsp作为默认的前端引擎,常见的过滤方式与jsp相同,不做赘述。 

CSRF防范 

Struts1提供了一个生成并验证Token的api(isTokenVaild),在检查是否防范了CSRF的时候,可以查看应用程序是否使用了这个API(也可以查看提交的请求包中是否包含org.apache.struts.taglib.html.TOKEN这个变量)。如果未使用,就可以检查是否在Filter之类的地方做了统一的自己实现的CSRF token验证防范。 

Struts1提供的Token值是存储在SESSION中的,因此这里就存在一个bug。由于Token在session中保存的变量名不变,因此如果一个用户打开了多个窗口,只有最后一个窗口设置的token值有效。这里需要多加注意。 

其他 

此外,Struts1有个特性:一个Action类在程序周期中只有一个实例,常驻内存。因此,在这个类中的属性和变量是共享的,不同用户访问的不同请求都是如此。因此如果程序中的逻辑依靠Action内部变量传送敏感信息,则其他用户也可能改写、读取。 

Struts2的白盒安全测试方法 

Struts2的安全测试主要方法论与S1一致,也多是通过查看struts.xml和web.xml中的配置,了解url->action->view的关系,以及不同url中涉及到的过滤器、拦截器、验证器(一般在validation.xml和className-validation.xml中配置)的关系。了解了这些,在头脑中有一个清晰的数据流脉络,然后再检查这些控制措施是否做到位,是否有疏漏即可。一般来说,S2的控制大都在拦截器和验证器中进行,常见的有是否登录、文件上传格式检查、参数有效性检查等。S2默认提供了很多拦截器,做了以上功能,这些在下面的安全特性中会提及。 

Struts2的安全特性 

参数获取 

与S1不同,S2中的参数获取虽然也可以通过Request.getParamter()方法,但是很少使用。因为action类中定义过getter/setter方法的变量,如果用户在请求中提交了同名的变量,框架会自动将其值注入到action实例中的对应变量中去,并且会做响应的类型转换。这一切是通过defaultStack中默认的Param拦截器实现的,利用拦截器,在action执行前,将用户传入的数值使用Request.getParamter()获取后并经过解析自动注入。 

这一点请一定注意。因为如果action中的内部成员变量之前有一个默认值,一旦用户提交了同名变量,就可以覆盖此值。这样就会直接导致后续依赖此默认值的逻辑发生重大变化。 

文件操作 

下载文件没有限制,需要自行编写代码控制。 

上传文件,S2默认有一个FileUploadInterceptor的拦截器,提供了三种限制方法,都在struts.xml中配置:

allowedTypes(允许文件的mime-type值,可伪造) 

maxmumSize(允许文件最大的字节数) 

allowedExtensions(允许文件的扩展名)

由于早期S2框架文档的误导,提供的例子程序中只限制了allowedTypes,因此导致多数s2应用程序存在修改http包修改mime-type导致任意上传漏洞。因此在做安全测试的时候,一定要检查是否设置了allowedExtensions作为白名单,而不单单是allowedTypes。另外即使做了扩展名限制,请注意这个可能还存在多扩展名文件的问题。 

如果上传没有使用默认的FileUploadInterceptor,请检查程序逻辑中是否对文件上传做了严格的限定。 

CSRF防范 

S2中也提供了防范重复提交的Token机制。与S1不同的是此次他是使用TokenInterceptor这个拦截器的方式,在action执行前统一进行验证。Token值也是保存在session中,因此同样存在S1框架中Token的bug。 

此外,这个Token机制还有个可以被绕过的0day漏洞:由于TokenInterceptor在验证用户提交上来的请求时,先从用户请求中的struts.token.name值作为session中的key,然后比对用户请求中提交的token值是否与session中key对应的值相匹配,如匹配则通过。但是,如果攻击者预先知晓session中已保存的一个值,例如username=admin,则攻击者可以直接将csrf包中的struts.token.name设置为username,然后token值设置为admin,即可轻易绕过csrf
token防范。 

因此,如果经检查的应用中使用了默认的token拦截器,请提醒开发人员弥补以上不足。如自行实现防重复提交的代码,请仔细检查其逻辑的严密性。 

动态方法调用 

Struts2中存在一个特性,叫做动态方法调用。当你请求actionName!methodName.action这样的URL时,框架不会调用action中的默认入口execute(),而是会寻找action中名叫methodName的方法,并直接调用。通过这种方式,可能暴露action类中未经过验证的内部接口,也可能绕过一些权限验证。 

因此,在测试过程中,如果程序本身没有使用到这个特性,请建议RD在struts.xml中设置一个constant将struts.enable.DynamicMethodInvocation属性设置为false,禁止此特性。 

前端模板 

S2自带的taglib中的变量输入都经过了自动html转义。一般无问题。但是请注意参数名前带感叹号,则表示没有转义。安全检测时请务必注意。 

如果使用其他模板引擎,请根据其他引擎的过滤规则进行检查。 

其他 

与s1不同,s2中每一个请求对应一个不同的action实例,没有action实例中变量共享的问题。 

S2的action中execute方法,根据方法返回的值来决定最后调用哪一个view模板。因此,结合动态方法调用和自动变量注入的特性,如请求actionName!getUsername.action?username=pass。而action中对应“pass”这个返回结果的view又是个包含敏感信息的模板,就可能产生问题。因此在安全测试的过程中需要特别注意。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息