WEB程序防SQL注入攻擊程序

場景: WEB程序容易被SQL注入攻擊,攻擊原理是在請求參數中傳入非法字符,造成SQL語句出現出現異常情況,已達到攻擊者想要的結果。

分析: 一般的攻擊者都是在傳入的請求參數上做文章,所以我們重點檢查的是request的參數,判斷request請求參數是否有非法字符,及數據庫關鍵字,如果有即判定爲SQL注入,否則通過。一般在WEB應用中都採用FILTER技術來處理此類問題,以下類適用於ORACLE,其他數據庫請修改SqlInjectFilter類中的static{ }內的關鍵字。

新增功能: 驗證POST攻擊,精簡驗證列表,優化驗證框架

解決:

1. 配置FILTER,配置位置爲 /WEB-INF/web.xml

 <filter>
       <filter-name>SqlInjectFilter</filter-name>
      <filter-class>SqlInjectFilter</filter-class>
      <init-param>
          <param-name>enabled</param-name>
           <param-value>true</param-value>
       </init-param>
       <init-param>
          <param-name>failthPath</param-name>
           <param-value>/failth.jsp</param-value>
       </init-param>
    </filter>
    <filter-mapping>
       <filter-name>SqlInjectFilter</filter-name>
       <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
       <filter-name>SqlInjectFilter</filter-name>
       <url-pattern>*.do</url-pattern>
    </filter-mapping>

 

說明:

    1. <filter-class>SqlInjectFilter</filter-class> 爲類全路徑,可以根據具體情況修改

    2.  這裏判定是否啓用,默認是啓用,否則將  <param-value>true</param-value> 修改爲  <param-value>false</param-value>

      <init-param>
          <param-name>enabled</param-name>
           <param-value>true</param-value>
       </init-param>

    3. 這是判定SQL注入後跳轉的頁面,根據實際情況修改 <param-value>/failth.jsp</param-value> 中的 /failth.jsp

       <init-param>
          <param-name>failthPath</param-name>
           <param-value>/failth.jsp</param-value>
       </init-param>

 

2. 新建FILTER類: SqlInjectFilter ; 2. 配置FILTER

 

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
* @ClassName: SqlInjectFilter
* @Description: TODO V2.0
* @author fasake [email protected]
* @date 2012-12-20 下午8:53:34
*
 */
public class SqlInjectFilter implements Filter {
 protected Log log = LogFactory.getLog(getClass());
 protected static Vector list = new Vector();
 protected String enabled = "true";
 protected String failthPath = "/TaxWeb/failth.jsp";

 public void destroy() {
  // TODO Auto-generated method stub

 }

 public void doFilter(ServletRequest arg0, ServletResponse arg1,
   FilterChain arg2) throws IOException, ServletException {
  // TODO Auto-generated method stub
  HttpServletRequest httpServletRequest = (HttpServletRequest) arg0;
  HttpServletResponse httpServletResponse = (HttpServletResponse) arg1;
  //獲取GET方法請求參數串
  String queryString = httpServletRequest.getQueryString();
  
        //是否啓動,web.xml中配置的初始化參數
  if (enabled.equalsIgnoreCase("true")) {
   //開始XSS(METHOD:GET)和sql注入檢測
   boolean isXssFind = false;
   if(queryString!=null && !queryString.equalsIgnoreCase("null")){
    String src = java.net.URLDecoder.decode(queryString,"GB2312");
    src  += "_"+queryString;
    if(src!=null && !src.equalsIgnoreCase("null")){
     String keyword = "";
     for (int i = 0; i < list.size(); i++) {
       keyword = list.get(i).toString();
       if(src.indexOf(keyword)!=-1){
        isXssFind = true;
        break;
       }
     }
     if(isXssFind){
      log.error("發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
      httpServletRequest.setAttribute("errorMsg", "發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
      httpServletRequest.getSession(true).setAttribute("injectKey","發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
      httpServletRequest.getSession().invalidate();
      httpServletResponse.sendRedirect(failthPath);
       throw new java.lang.IllegalAccessError();
     }
    }
   }
   //開始XSS(METHOD:POST)和sql注入檢測
   if(!isXssFind){
    arg2.doFilter(new RequestWrapperXSS(httpServletRequest,httpServletResponse,list,failthPath), arg1);
   }
  }else{
   arg2.doFilter(arg0, arg1);
  }

 }

 
 /**
  * 初始化
  */
 public void init(FilterConfig arg0) throws ServletException {
  // TODO Auto-generated method stub

  enabled = arg0.getInitParameter("enabled");
  failthPath = arg0.getInitParameter("failthPath");
  if (enabled == null || "".equals(enabled)) {
   enabled = "true";
  }
  if (failthPath == null || "".equals(failthPath)) {
   enabled = "/TaxWeb/failth.jsp";
  }
  log.info("SQL注入檢測初始化完成");
 }

 static {
  list.add("'");
  list.add("(");
  //list.add("or");
  //list.add("and");
  list.add("[");
  list.add("<");
  list.add(".."+File.separator);
  // 請求參數不能能有腳步
  list.add("script");
  list.add("+");
  //list.add("-");
  list.add("*");
  list.add("%");
 }
}

/**
 *
* @ClassName: RequestWrapperXSS
* @Description: TODO 自定義HttpServletRequest
* @author fasake [email protected]
* @date 2012-12-20 下午7:16:00
*
 */
class RequestWrapperXSS extends HttpServletRequestWrapper {
 protected Log log = LogFactory.getLog(getClass());
 private HttpServletRequest request;
 private HttpServletResponse serlvetResponse;
 private boolean isXssFind=false;
 private Vector keywords;
 private String failForwardPath;
 public RequestWrapperXSS(HttpServletRequest servletRequest) {
  super(servletRequest);
  this.request = servletRequest;
 }
 /**
  *
  * @param servletRequest
  * @param serlvetResponse
  */
 public RequestWrapperXSS(HttpServletRequest servletRequest,HttpServletResponse serlvetResponse) {
  super(servletRequest);
  this.request = servletRequest;
  this.serlvetResponse = serlvetResponse;
 }
 public RequestWrapperXSS(HttpServletRequest servletRequest,HttpServletResponse serlvetResponse,Vector keywords,String failForwardPath) {
  super(servletRequest);
  this.request = servletRequest;
  this.serlvetResponse = serlvetResponse;
  this.keywords = keywords;
  this.failForwardPath = failForwardPath;
 }
 /**
  * 覆蓋
  */
 public String[] getParameterValues(String name){
  String[] values = super.getParameterValues(name);
  //log.debug("parameter name: "+name+" value:"+values.toString());
  try {
   xssCheck(values,keywords);
  } catch (IllegalAccessError e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   throw e;
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return values;
 }
 /**
  * 覆蓋
  */
 public String getParameter(String para){
  String postStrInfo = super.getParameter(para);
  //log.debug("parameter name: "+para+" value:"+postStrInfo);
  try {
   //log.debug("parameter name: "+para);
   log.debug("(檢測)接收到的["+request.getMethod()+"]請求參數值: " + postStrInfo); 
   xssCheck(postStrInfo,keywords);
   
   
  } catch (IllegalAccessError e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   throw e;
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return postStrInfo;
 }
 
  public ServletInputStream getInputStream() {
   //ServletInputStream
   ServletInputStream stream = null; 
   //POST表單信息
   String postStrInfo = null;
    try{
      stream = request.getInputStream();
      byte[] buffer = IOUtils.toByteArray(stream);
      postStrInfo = new String(buffer,"GB2312");
      //拆分請求參數串
      String[] args = postStrInfo.split("\r\n");
      for (int i = 0; i < args.length; i++) {
       String line  = args[i];
       //過濾分隔符,和請求參數名稱
       if(line.trim().startsWith("-------------------") || line.trim().startsWith("Content-Disposition")  || line.trim().equals("")){
        log.debug("(忽略)接收到的["+request.getMethod()+"]請求參數值: " + line); 
        continue;
       }
       log.debug("(檢測)接收到的["+request.getMethod()+"]請求參數值: " + line); 
       xssCheck(line,keywords);
      }
      
      //驗證完成
      final ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
      //生成新的ServletInputStream
      ServletInputStream sis = new ServletInputStream() {
       public int read() throws IOException {
        // TODO Auto-generated method stub
        return bais.read();
       }
      };
      stream = sis;
    }catch(IOException e){
     e.printStackTrace();
    } 
   
   return  stream;
  }
 /**
 * @Title: xssCheck
 * @Description: TODO 檢測XSS和SQL注入處理類
 * @param @param postStrInfo
 * @param @throws IOException
 * @param @throws IllegalAccessError
 * @return void
 * @throws
 */
 private void xssCheck(String postStrInfo,Vector array) throws IOException,
   IllegalAccessError {
  if(postStrInfo==null)return;
  String src = postStrInfo==null?"null":postStrInfo.toLowerCase();
  src = java.net.URLDecoder.decode(src,"GB2312");
  //驗證XSS中是否包含相關關鍵字
  if(src!=null && !src.equalsIgnoreCase("null")){
   String keyword = "";
   for (int i = 0; i < array.size(); i++) {
    
     keyword = array.get(i).toString();
     if(src.indexOf(keyword)!=-1){
      isXssFind = true;
      break;
     }
   }
   if(isXssFind){
    log.error("發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
    request.setAttribute("errorMsg", "發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
    request.getSession(true).setAttribute("injectKey","發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
    request.getSession().invalidate();
    serlvetResponse.sendRedirect(failForwardPath);
     throw new java.lang.IllegalAccessError();
   }
  }
 }
 /**
  *
 * @Title: xssCheck
 * @Description: TODO 檢測XSS
 * @param @param values
 * @param @param array
 * @param @throws IOException
 * @param @throws IllegalAccessError
 * @return void
 * @throws
  */
 private void xssCheck(String[] values,Vector array) throws IOException,IllegalAccessError {
             if(values==null){return;}
             for (int j = 0; j < values.length; j++) {
    String src = java.net.URLDecoder.decode(values[j],"GB2312");
    //驗證XSS中是否包含相關關鍵字
    if(src!=null && !src.equalsIgnoreCase("null")){
     String keyword = "";
     for (int i = 0; i < array.size(); i++) {
       keyword = array.get(i).toString();
       if(src.indexOf(keyword)!=-1){
        isXssFind = true;
        break;
       }
     }
     if(isXssFind){
      log.error("發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
      request.setAttribute("errorMsg", "發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
      request.getSession(true).setAttribute("injectKey","發現疑爲跨站腳本攻擊,檢測判斷請求地址包含非法字符:"+java.net.URLEncoder.encode(keyword,"GB2312"));
      request.getSession().invalidate();
      serlvetResponse.sendRedirect(failForwardPath);
       throw new java.lang.IllegalAccessError();     }
    }
   }
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章