SQL注入和SCRIPT注入,是一个烦人的东西,那么这个问题该怎么解决呢?下面就说一说如何解决这个问题。
    在项目一开始,如果就考虑到这个问题的话,那是可以完全避免的。
    反script注入:在jsp页面中解决,增删查修审都用struts标签 ,是没有任何问题的。如果是html标签的话,用jstl标签也可以完全解决。
    那么如果用到文本编辑器的时候,又该怎么解决啊?我的反SCRIPT注入就可以解决这个问题了。
    反sql注入:如果是jdbc的话,不要用Statement,用PreparedStatement就可以避免。如果用hibernate的话,用 Criteria查询就可以解决这个问题。

    如何是在项目快完结的时候才发现这个问题,那该怎么解决啊?
    apache提供了工具类:org.apache.commons.lang.StringEscapeUtils,它里面有对应的方法解决这个问题。
    下面是我自己提供一种方法。

    为了实现反SQL注入和反SCRIPT注入,本例应用反射技术和责任链模式实现了这个功能。它对于系统来说是可插拨的,这样就实现了与系统的松散耦合。
    它的主要思想是:把Form对象,PO对象以及VO等对象中的String型属性的值或者String类型的参数进行过滤后重新封装为原有类型的对象。在获取对象的时候应用了 java反映技术,
在进行过滤的时候,实现了链式过滤。这样做,就是为了达到可维护性,可扩展性,可重用性以及灵活性的目的。
    以下是源代码:


package net.better_best.www.utils.filter;
public class Request {
    // 存储需要过滤的字符串
    private String requestStr;
    public String getRequestStr() {
        return requestStr;
    }
    public void setRequestStr(String requestStr) {
        this.requestStr = requestStr;
    }
}


package net.better_best.www.utils.filter;

public class FilterConstant {
 //定义sql过滤的内容
 public static String[][] SQL_FILTER = {
  {";",""},
  {"'","''"},
  {"--",""},
  {"%",""}
  };
  //定义script过滤的内容
 public static String[][] SCRIPT_FILTER = {
  {"(<[i|I][n|N][p|P][u|U][t|T])([^>]*)(/>)",""},
  {"(<[i|I][n|N][p|P][u|U][t|T])([\\s\\S]*)(</[i|I][n|N][p|P][u|U][t|T]>)",""},
  {"(<[t|T][a|A][b|B][l|L][e|E])([^>]*)(/>)",""},
  {"(<[t|T][a|A][b|B][l|L][e|E])([\\s\\S]*)(</[t|T][a|A][b|B][l|L][e|E]>)",""},
  {"(<[d|D][i|I][v|V])([^>]*)(/>)",""},
  {"(<[d|D][i|I][v|V])([\\s\\S]*)(</[d|D][i|I][v|V]>)",""},
  {"(<[b|B][u|U][t|T][t|T][o|O][n|N])([^>]*)(/>)",""},
  {"(<[b|B][u|U][t|T][t|T][o|O][n|N])([\\s\\S]*)(</[b|B][u|U][t|T][t|T][o|O][n|N]>)",""},
  {"(<[s|S][c|C][r|R][i|I][p|P][t|T])([^>]*)(/>)",""},
  {"(<[s|S][c|C][r|R][i|I][p|P][t|T])([\\s\\S]*)(</[s|S][c|C][r|R][i|I][p|P][t|T])(>)",""},
  };
}



package net.better_best.www.utils.filter;

public interface IFilter {
    void doFilter(Request request, FilterChain chain);
}



 

package net.better_best.www.utils.filter;

public class SqlFilter implements IFilter {
    @Override
    //进行sql过滤
    public void doFilter(Request request, FilterChain chain) {
        if (request != null) {
         String strRequest = request.getRequestStr();
         String[][] sqlFilter = FilterConstant.SQL_FILTER;
         for (String[] strings : sqlFilter) {
          strRequest = strRequest.replace(strings[0], strings[1]);
   }
         request.setRequestStr(strRequest);
        }
        chain.doFilter(request, chain);
     
    }
}




package net.better_best.www.utils.filter;

public class ScriptFilter implements IFilter {
 @Override
 //进行script过滤
 public void doFilter(Request request, FilterChain chain) {
  if (request != null) {
   String strRequest = request.getRequestStr();
   String[][] scriptFilter = FilterConstant.SCRIPT_FILTER;
         for (String[] strings : scriptFilter) {
          strRequest = strRequest.replaceAll(strings[0], strings[1]);
   }
   request.setRequestStr(strRequest);
  }
  chain.doFilter(request, chain);

 }
}




package net.better_best.www.utils.filter;

public enum FilterType {
 SQL_TYPE,SCRIPT_TYPE ;
}


package net.better_best.www.utils.filter;


public class FilterHelper {
 /*
  * 生成过滤链条 参数:String type:过滤类型 返回:FilterChain; 根据过滤类型产生过滤链条
  */
 public static FilterChain createFilterChain(FilterType type,FilterChain fChain) throws Exception {
  if (type == null)
   return null;
  else if (type.equals(FilterType.SQL_TYPE))
   return fChain.addFilter(new SqlFilter());
  else if (type.equals(FilterType.SCRIPT_TYPE))
   return fChain.addFilter(new ScriptFilter());
  else
   return null;
 }

 /*
  * 把要过滤的字符串封装成Request对象
  */
 public static Request init(String str) throws Exception {
  if (str == null || str == "")
   return null;
  Request request = new Request();
  request.setRequestStr(str);
  return request;
 }

 /*
  * 对Request对象进行循环过滤
  */
 public static String result(Request request, FilterChain fChain)
   throws Exception {
  if (request == null || fChain == null || fChain.size() == 0)
   return null;
  fChain.doFilter(request, fChain);
  return request.getRequestStr();
 }
}


package net.better_best.www.utils.filter;
import java.util.ArrayList;
import java.util.List;

public class FilterChain implements IFilter {
    // 使用 List 保存过滤器
    private List<IFilter> filters = new ArrayList<IFilter>();
    private int index = 0;
    // 用于添加过滤器,可以添加实现了IFilter接口的FilterChain
    public FilterChain addFilter(IFilter f) {
        this.filters.add(f);
        return this;
    }
    @Override
    public void doFilter(Request request,  FilterChain chain) {
        // 判断是否是否遍历到 List 的最大值,如果是 return
        if (index == filters.size())
            return;
        // 逐一获取过滤器
        IFilter f = filters.get(index);
        // 此过滤器链的下标,是遍历过滤器的索引
        index++;
        // 使用列表中的第index个过滤器,将更改后的 request ,chain 传进去,
        f.doFilter(request,chain);
        index = 0;
    }
    public int size(){
     return filters.size();
    }
}


package net.better_best.www.utils;

import java.lang.reflect.Field;

import net.better_best.www.utils.filter.FilterChain;
import net.better_best.www.utils.filter.FilterHelper;
import net.better_best.www.utils.filter.FilterType;

public class Filter {
 /*
  * 参数:Object,接收ActionForm,Plain Object,View.Object的属性值应为单值类型,不能为复合类型或数组类型;
  * 参数:FilterType,定义需要过滤的类型; 返回值:Object; 作用:根据已定义的过滤规则,过滤所传入Object值;
  */
 public static Object objectFilter(Object obj, FilterType... types) {
  if (obj == null)return obj;
  Class clazz = obj.getClass();
  if (clazz.isArray() || clazz.isInterface() || clazz.isPrimitive())return obj;
  Field[] fds = clazz.getDeclaredFields();
  for (Field field : fds) {
   if (field.getType().getName().equals("java.lang.String")) {
    field.setAccessible(true);
    Object before = null;
    try {
     before = field.get(obj);
    } catch (IllegalArgumentException e) {
     e.printStackTrace();
    } catch (IllegalAccessException e) {
     e.printStackTrace();
    }
    if (before != null)
     try {
      field.set(obj, doFilter(before.toString(), types));
     } catch (IllegalArgumentException e) {
      e.printStackTrace();
     } catch (IllegalAccessException e) {
      e.printStackTrace();
     }
   }
  }
  return obj;
 }

 /*
  * 按照定义好的过滤规则,进行过滤; 参数:String str ,待过滤字符串 返回:String; 已过滤字符串
  */
 public static String doFilter(String str, FilterType... types) {
  if (str == null || str == "")
   return null;
  FilterChain fChain = new FilterChain();
  String result = "";
  try {
   if (types.length == 0) {
    FilterType[] filterTypes = FilterType.values();
    for (FilterType filterType : filterTypes) {
     fChain = FilterHelper.createFilterChain(filterType, fChain);
    }
   } else {
    for (FilterType type : types) {
     fChain = FilterHelper.createFilterChain(type, fChain);
    }
   }
   if (fChain == null) {
    result = str;
   } else {
    result = FilterHelper.result(FilterHelper.init(str), fChain);
   }

  } catch (Exception e) {
   e.printStackTrace();
  }
  return result;
 }
}



     使用方法:调用Filter的两个方法,就可以了。

    以上内容为全部代码;


      欢迎对本文的内容提出不同见解和质疑,不胜感激。
      如果疑问,可发邮件联系我。可发邮件索取源代码。
      



   

Feedback

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-13 16:43 by 超级笨笨
可以,对我有帮助

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-14 15:41 by Lancelot
为什么要做这些无用功???

正解应该是表单提交时,允许用户提交各种数据,通过“SET PARAMETER”方式传入sql中(不管是自己,还是通过ORM都可以很容易实现),这样来解决sql注入。

至于script注入,只需要再在上面的基础上,根据需要显示出相应的格式就可以了,比如:“jstl”的“out” 可以设置 “escapeXml”、“struts”的“write”可以设置“flter”。

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-15 11:19 by java小爬虫
@Lancelot
你好,你说的东西,我都试过了,都是可以的。

但是有一个问题:

就是AJAX方式,查询结果是用字符串拼接起来的,这种情况怎么解决啊?我目前还没有找到结果办法。谢谢...

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-15 11:20 by java小爬虫
@超级笨笨
欢迎对以上代码挑刺...

呵呵呵

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-15 11:53 by Lancelot
以struts为例,只要调用org.apache.struts.util.ResponseUtils.filter(String value),方法就是了,有什么问题???

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-15 13:00 by java小爬虫
@Lancelot

举个例子:

public ActionForward getNewsList(
ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {

try {
PrintWriter out = init(request, response);
PageInfo pageinfo = newsService.getNewsPerPage(
ParameterCode.curpage_first, ParameterCode.pageSize_10, "");
List<NewsTable> newsList = pageinfo.getPagedata();
if (newsList != null && newsList.size() > 0) {
out.print("<UL>");
for (NewsTable news : newsList) {

out.print("<li>.<a href='aa.html' title='"
+ news.getNewsTitle() + "' >"
+ news.getNewsTitle() + "</a></li>");

}
out.print("</UL>");
out.close();
}
}
catch (Exception e) {

e.printStackTrace();
}
return null;
}


ajax会调用这个方法,那么org.apache.struts.util.ResponseUtils.filter(news.getNewsTitle())就这样过滤吗?

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-15 13:57 by Lancelot
虽然不赞成你这种写法,不过在你这中应用场景里就是这么用,这总比你费尽周折的造出那么个东西来的要好。

# re: 反SQL注入和SCRIPT注入-------------责任链模式的应用  回复  更多评论   

2010-01-15 18:05 by java小爬虫
@Lancelot
其实,在项目开始的时候,就考虑script和sql注入,是可以完全避免这个问题的。


但是如果到了项目后期的话,我这个东西还是可是用的,自我感觉良好,还可以用于系统定义的非法字符的过滤,呵呵呵,


不过,你的建议让我学到了不少东西,谢谢你...

只有注册用户登录后才能发表评论。


网站导航: