我们目前的系统中使用了struts2框架,该版本是2.3.32,但近期Apache struts发布了一项struts的安全漏洞说明,具体如下:
Apache Struts2 远程代码执行漏洞(S2-048)
发布日期:2017年7月7日
CVE ID:CVE-2017-9791
受影响的版本:
Apache Struts Version: 2.3.x
不受影响的版本:
Apache Struts Version:2.5.10.1
综述:
2017年7月7日,Apache Struts发布最新的安全公告,Apache Struts2的Struts1插件存在远程代码执行的高危漏洞,漏洞编号为CVE-2017-9791(S2-048)。攻击者可以构造恶意的字段值通过Struts2的Struts1的插件,远程执行代码。
相关链接如下:
https://cwiki.apache.org/confluence/display/WW/S2-048
规避方案
- 关闭Showcase插件。
- 受影响的用户可以升级到2.5.10.1版本。
- 开发者通过使用resource keys替代将原始消息直接传递给ActionMessage的方式。 如下所示:
messages.add("msg", new ActionMessage("struts1.gangsterAdded", gform.getName()));
不要使用如下的方式:
messages.add("msg", new ActionMessage("Gangster " + gform.getName() + " was added"));
- 在非必要的情况下禁用struts2-struts1-plugin插件。将struts2-struts1-plugin-2.3.x.jar文件从 “/WEB-INF/lib”目录中移动到其他文件夹或者删除。
根据apache struts的安全漏洞说明,我们的struts版本刚好是这次说的有问题的版本,因此需要根据官方建议升级为2.5.10.1。
但是综合项目实际情况后发现,升级到2.5.10.1的struts2后,官方的规范说明明确指出需要使用jdk7以上版本:
因此,若要升级struts2,则必须同时升级目前项目中jdk6版本到jdk7。
考虑到项目实际情况,发现如上述的方式改动,升级jdk6到jdk7后,出现的问题将会更大,因此分析研究后决定直接把struts2的框架替换为spring mvc,在解决本次问题的同时,向目前更主流的框架靠拢。
在整个改造过程中问题诸多,以下是部分问题及解决办法记录,供以后参考:
1、改造之前,尝试运行原来的项目,其中有两个项目mobileFront和mobileFrontQuery,在把两个项目都加入到同一个tomcat的时候报错,提示如下:
Could not publish server configuration for Tomcat v7.0 at localhost.
Multiple Contexts have a path of "/mobileFront".
意思是要部署名为mobileFront的项目,但是现在已经存在了一个。
原因是mobileFront和mobileFontQuery的部署名称都是mobileFront,在同一个tomca中部署两个相同部署名称的项目是不被允许的。
解决办法是更改其中任意一个的部署名称,使其不冲突,具体更改过程如下:
右键项目--》 选择properties --》 点击web project settings --》把context root后的名称改为要部署的新名称 --》
打开工作空间,也就是项目文件的存储目录,找到要更改的项目 --》打开.settings文件夹 --》 用编辑器打开org.eclipse.wst.common.component文件 --》把文件中原本项目相关的名称都改为新的项目部署名并保存 --》重启eclipse。
2、依次配置完web.xml,applicationcontext.xml和springmvc.xml,并在controller类以及相应方法中加入相应注解后启动项目,抛出如下异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MMarketAction1': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.huateng.mmarket.service.MMarketService
意思是创建MMarketAction1这个bean失败,因为autowire无法注入MMarketService。
原因是在配置web.xml文件时少了一个spring的监听器:
<listener>
<description>spring监听器</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
在web.xml中加入此监听器,再次启动tomcat则不再跑出上述异常。
3、启动tomca时抛出异常:
java.lang.NoSuchMethodError: org.springframework.web.bind.annotation.RequestMapping.consumes()[Ljava/lang/String;
意思是在requestMapping的方法不存在,这个是使用@RequestMapping注解生成url是抛出异常。
原因是在项目中同时存在了两个spring-web的jar包,一个3.0.5版本,一个3.1.1版本,这两个包中都有这个类,包名一样,导致走到这里无法确定该用哪个,最终找不到。
解决办法是去掉3.0.5的jar包,重启tomca后正常。
4、启动tomcat没有抛出异常,但是访问项目时始终提示404,最终发现在tomcat的项目部署路径下的WEB-INF中没有web.xml文件,也就是说这个项目并没有成功部署到tomcat中。
原因是在build path中少了webapp的引入,导致部署的时候并没有扫描webapp下的文件,原本build中如下:
解决办法是在build中加入webapp的文件夹,加入后如下:
然后clean之后重启tomcat,可正常访问。
5、有同事在正常启动tomcat之后,却无法正常访问,原因是部署名并不是项目名,而他使用项目名称访问,自然就一直是404。解决办法是把部署名称换成项目名称,或者使用实际部署名称访问。
6、struts的action类更改为spring mvc的controller,原struts2情况下,所有action都继承了ActionSupport,并在struts.xml中进行了类似下边的配置:
<action name="rcvSpdbPage" class="com.RcvSpdbPageAction"
method="receive"></action>
name定义url,class定义url对应的具体类,method定义入口方法。
改为springmvc后,去掉对ActionSupport的继承,去掉struts.xml的配置,取代的是在类名上加@controller注解以及在方法上加@RequestMapping注解。
还有一种情况是,需要返回jsp页面,原struts中配置如下:
<action name="rcvSPDBReceive" class="com.RcvSpdbAction"
method="receive">
<result name="signPage">/CmuSpdbResultSign.jsp</result>
</action>
改为springmvc后,除开上一中无返回值一样的改法外,还需要更改方法的返回值为ModelAndView
同时在代码中return “signPage”的地方,改为
return new ModelAndView("/CmuSpdbResultSign.jsp");