零全零美(www.zzgwt.com)
          生活中的很多事情,并不像If...Else那么簡單!
          posts - 96,comments - 52,trackbacks - 0
           在系統開發中,與用戶交互的地方,例如表單輸入,瀏覽器URL傳參都是系統安全的敏感地帶。傳統的客戶端JavaScript驗證只能擋君子而不能攔小人,因為用戶一旦將JS禁用,我們就無能為力。于是人們說最安全的方式還是在服務器端驗證。但是這種最安全的方式卻是很麻煩的做法!因為我們無法只單單的在服務器端驗證,我們還需要做客戶端傳統驗證,這樣一來同一套驗證,客戶端一次,服務器端一次,暫且不考慮執行的效率,單單是開發的效率就很讓人抓狂了!尤其是對URL傳參的驗證,難道我們對每一個URL傳遞參數的地方都必須寫一堆的驗證代碼嗎?
           如果有這樣一種方法能夠通過一個過濾器能夠一次性的攔截獲取所有的用戶輸入,那么我們就可以只通過這個過濾器來做基礎的安全性驗證,例如我們可以過濾SQL語句,過濾非安全字符等等,而把業務規則驗證留給程序員去實現,就將大大的加快開發效率,同時也可以構建一個通用的用戶輸入驗證框架,減少與程序的緊耦合!
           例如我們將所有用戶輸入中的"<"改為"&lt;",將所有的">"改為"&gt;"
           本文試圖尋找一種方法來解決這個問題!
           
           關于對裝飾模式的具體說明,可以自行Google一下,或者可以查看此文:裝飾Servlet Request對象,建議想了解原理的讀者先閱讀一下這篇文章!
           首先我們創建一個filter,讓它可以攔截所有的請求!
           <filter>
            
          <filter-name>userInputFilter</filter-name>
            
          <filter-class>
             com.djwl.core.security.UserInputFilter
            
          </filter-class>
           
          </filter>
           
          <filter-mapping>
            
          <filter-name>userInputFilter</filter-name>
            
          <url-pattern>/*</url-pattern>
           
          </filter-mapping>

          package com.djwl.core.security;

          import java.io.IOException;

          import javax.servlet.FilterChain;
          import javax.servlet.FilterConfig;
          import javax.servlet.ServletException;
          import javax.servlet.ServletRequest;
          import javax.servlet.ServletResponse;
          import javax.servlet.http.HttpServletRequest;

          /**
           * 功能描述:過濾用戶輸入的危險字符,及SQL語句<BR>
           * 
          @author 楊凱 <BR>
           * 時間:Jun 9, 2009 1:22:03 PM <BR>
           
          */

          public class UserInputFilter implements javax.servlet.Filter {

              
          public void destroy() {
                  
              }


              
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
                  HttpServletRequest request 
          = (HttpServletRequest)servletRequest;
                  request.setCharacterEncoding(
          "gbk");
                  
                  
          //重點是這句,該處我們運用裝飾模式構建一個自己的ServletRequest類
                  chain.doFilter(new UserInputFilterHttpServletRequestWrapper(request), servletResponse);
              }


              
          public void init(FilterConfig filterConfig) throws ServletException {
                  
              }


          }


          package com.djwl.core.security;

          import java.util.HashMap;
          import java.util.Map;

          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletRequestWrapper;

          import com.djwl.core.utils.V;

          public final class UserInputFilterHttpServletRequestWrapper extends HttpServletRequestWrapper {

              
          public final static Map characterMap = new HashMap();
              
              
          //對于一些我們不想讓該類驗證的值,例如我使用Tapestry開發,那么這些Tapestry框架自己的東西,我們忽略掉!
              static{
                  characterMap.put(
          "formids""");
                  characterMap.put(
          "seedids""");
                  characterMap.put(
          "submitmode""");
                  characterMap.put(
          "sp""");
                  
              }

              
              
          //構造函數
              public UserInputFilterHttpServletRequestWrapper(HttpServletRequest request) {
                  
          super(request);
              }

              
              
          //驗證從頁面上提取單個值的情況,包括URL傳參
              @Override
              
          public String getParameter(String name) {
                  
          return  V.validate(super.getParameter(name));
              }

              
              
          //驗證從頁面上一次性獲取多個值的情況
              @Override
              
          public String[] getParameterValues(String name) {
                  
          //忽略一些我們的設定
                  if (characterMap.containsKey(name)) {
                      
          return super.getParameterValues(name);
                  }

                  String[] userinputs 
          = super.getParameterValues(name);
                  
          if (userinputs == null{
                      
          return null;
                  }

                  
          //逐一判斷
                  String[] results = new String[userinputs.length];
                  
          int i=0;
                  
          for (String string : userinputs) {
                      results[i] 
          = V.validate(string);
                      i
          ++;
                  }

                  
          return results;      
              }

          }


           
          package com.djwl.core.utils;

          import java.util.regex.Matcher;
          import java.util.regex.Pattern;

          import org.apache.commons.lang.StringUtils;

          import com.djwl.core.MisException;

          public class V {
              
              
          /**
               * 功能描述:改變用戶輸入<BR>
               * 
          @param str
               * 
          @return
               * 
          @author:楊凱<BR>
               * 時間:Nov 24, 2009 12:07:57 PM<BR>
               
          */

              
          private static String escape(String str){
          //        str = StringEscapeUtils.escapeSql(str);
          //        str = StringEscapeUtils.escapeHtml(str);
          //        //str = StringEscapeUtils.escapeJavaScript(str);
          //        str = str.replaceAll("#", "");
                  str = str.replaceAll("<""&lt;").replaceAll(">""&gt;");
                  str 
          = str.replaceAll("\r\n""<BR>");
                  str 
          = str.replaceAll("null"" ");
                  
          return str;
              }

              
              
          /**
               * 功能描述:截取危險字符<BR>
               * 
          @param str
               * 
          @return
               * 
          @author:楊凱<BR>
               * 時間:Nov 24, 2009 12:08:08 PM<BR>
               
          */

              
          private static Boolean contains(String str){
                  
          //這里我們可以根據自己的邏輯,編寫適當的正則表達式判斷
                  String regexp = "\\b(drop|delete|update|insert|select|call|exec|set|declare|script|link)\\b";
                  Matcher matcher 
          = Pattern.compile(regexp).matcher(str.toLowerCase());
                  
          if (matcher.find()) {
                      
          throw new MisException("用戶輸入中含有非法字符");
                  }
           else {
                      
          return true;
                  }

              }

              
              
          /**
               * 功能描述:驗證字符串<BR>
               * 
          @param str
               * 
          @return
               * 
          @author:楊凱<BR>
               * 時間:Jun 9, 2009 5:09:31 PM<BR>
               
          */

              
          public static String validate(String str){
                  
          if (StringUtils.isNotBlank(str) && contains(str)) {
                      
          return escape(str);
                  }

                  
          return null;
              }

              
              
          }


               需要說明的一點是,如果表單中有文件上傳的控件,意思是說如果from標簽中enctype="multipart/form-data" ,則該過濾器如果獲取用戶輸入,需要自行驗證,當然一個系統中有文件上傳的地方畢竟不多!所以造成的麻煩是很小的!
           

                 文章原創,轉載請以鏈接方式著名出處!【原創】運用裝飾模式截取用戶輸入構建通用驗證
          posted on 2009-11-24 12:15 零全零美 閱讀(1232) 評論(2)  編輯  收藏 所屬分類: 設計模式

          FeedBack:
          # re: 【原創】運用裝飾模式截取用戶輸入構建通用驗證
          2009-11-24 12:42 | 羅萊價格
          統中有文件上傳的地方畢竟不多  回復  更多評論
            
          # re: 【原創】運用裝飾模式截取用戶輸入構建通用驗證
          2009-11-24 17:04 | 零全零美
          暈啊,都是做廣告的!  回復  更多評論
            
          主站蜘蛛池模板: 桦南县| 湖州市| 盖州市| 巢湖市| 葵青区| 嘉定区| 安岳县| 安新县| 沁源县| 内江市| 沙坪坝区| 缙云县| 县级市| 昭觉县| 越西县| 安福县| 将乐县| 碌曲县| 什邡市| 娄底市| 汉源县| 永州市| 平江县| 鄄城县| 怀仁县| 即墨市| 卢湾区| 玉山县| 同心县| 崇礼县| 宜章县| 张家川| 洪湖市| 榆林市| 方正县| 文昌市| 聂拉木县| 烟台市| 永修县| 平顶山市| 清新县|