最近在做一些代码安全性检查,使用了Fortify。发现了一些曾经引以为豪的代码既然会出现高危的错误。希望各位达人给予帮助。
         设计初衷:共享WebApplicationContext,通过getBean(String beanName)取得对应的bean处理相应的业务逻辑。
public class BaseAction extends Action {
    
private WebApplicationContext wac;
    
protected ServletContext context;    
    
public void setServlet(ActionServlet actionServlet) {
        
super.setServlet(actionServlet);
        context 
= actionServlet.getServletContext();
        wac 
= WebApplicationContextUtils.getRequiredWebApplicationContext(context);
    }


    
protected Object getBean(String beanName) {
        
return wac.getBean(beanName);
    }

}
      高危错误代码:        
context = actionServlet.getServletContext();
        wac 
= WebApplicationContextUtils.getRequiredWebApplicationContext(context);
         错误原因分析:BaseAction继承自Action,单例实现。该类含有属性:wac与context,在多线程环境下不能保证这两个属性的合理逻辑。于是掉入了一个单例模式的陷阱。(请各位达人完善)
         解决方法:jdon(banq)给我的回复          
       
 banq:写的方法是高危,但是看你的方法内容,则没有关系。

你的方法内容是获得一个Web项目的一个单例,实际就是Spring容器,而且大部分是读,而不是读写并加。

单例陷阱我已经在以前帖子中说了,只有在单例+写+同步等操作下才可能死锁,因为代码不可控性,今天你注意没这么做,不代表其他无知的人不这么做,所以,这种singlton会被严谨的工具认为是高危,这是正确的。
 ME:谢谢 banq!
如果需要消除这段高危代码,需要如何重构.
因为只是存在读操作,我是否可以把wac与context定义为static(这样工具不会报错)

请问这样改会不会有问题?
  banq:不能用static,这样Spring容器中所有资源都不能随着你的WEB项目消失而消失。

主要问题在于你的setServlet(ActionServlet actionServlet)这个方法,这其实是一个初始化工作,试验在BaseAction的构造方法中首先实现,这样表示有前有后,可能不会报高危错误。

实在不行,做一个懒加载的方法,在这个方法中,检查一下wac是否为空,如果为,就进行初始化,不为空,就直接返回wac值。
去除setServlet方法,在getBean加入,如下,如果还不行,就每次老老实实的用WebApplicationContextUtils获得Spring实例:

protected Object getBean(String beanName) {
if(wac==null){
context 
= actionServlet.getServletContext();
wac 
= WebApplicationContextUtils.getRequiredWebApplicationContext(context);
}


return wac.getBean(beanName);
}