Todd

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            65 隨筆 :: 0 文章 :: 24 評論 :: 0 Trackbacks

          真是一切都逃不過session,看了DZ的formhash;struts token什么啊,就是個session,安全級別比驗證碼還低。
          看看別人的分析有益身心啊,看之,目前來講一切都逃不過session


          預期達到目標
          :

                 1、當用戶進行的是Refresh/Reload/Back/Forward操作、以及先BackSubmit操作時,僅僅是reloading先前的結果頁。

                 2、當用戶重復提交同一個任務操作時,后臺服務接收并處理第一次提交的任務,后面提交不起作用(不轉向也不提示)。

                 3、該功能具有公用性。

          基本形成思路:

                 1、在basic filter中實現公用性

                          if(true){//問題1:如何確定是否為重復提交

                                   ...

                                   chain.doFilter(request,response);

                          }else{

                                   //問題2:如何實現不轉向、不提示也不顯示空白頁

                          }

                 2、網上資料概括

                          a、提交表單后按鈕變灰/隱藏提交按鈕

                          b、在js里設置全局變量,提交后修改該變量的值,依據變量的值判斷是否重復提交

                                   var flag=true;

                                   function checkForm(){

                                             if (flag==false){

                                                      return;

                                             }

                                  

                                             flag=false;

                                             document.form1.submit();

                                  

                                   }

                          cstruts webwork沒有找到這個資料)

                                   //驗證事務控制令牌,<html:form >會自動根據session中標識生成一個隱含input代表令牌,防止兩次提交

                                   action中:

                                  

                                          //<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae">

                                  

                                          if (!isTokenValid(request))

                                              errors.add(ActionErrors.GLOBAL_ERROR,

                                                         new ActionError("error.transaction.token"));

                                          resetToken(request); //刪除session中的令牌

                                  

                                   action有這樣的一個方法生成令牌華

                                      protected String generateToken(HttpServletRequest request) {

                                  

                                          HttpSession session = request.getSession();

                                          try {

                                              byte id[] = session.getId().getBytes();

                                              byte now[] =

                                                  new Long(System.currentTimeMillis()).toString().getBytes();

                                              MessageDigest md = MessageDigest.getInstance("MD5");

                                              md.update(id);

                                              md.update(now);

                                              return (toHex(md.digest()));

                                          } catch (IllegalStateException e) {

                                              return (null);

                                          } catch (NoSuchAlgorithmException e) {

                                              return (null);

                                          }

                                  

                                      }          

                          d、用戶使用瀏覽器時,可以經常使用向后的按鈕,因此就有可能重復提交一個他們已經提交過的form,這樣就會帶來一個重復事務處理的問題。同樣,一個用戶也可能在接收到一個確認的頁面之前按下停止的按鈕,接著再次提交同一個form。對于這些情況,我們都想跟蹤并且禁止這些重復的提交,我們可以使用一個控制servlet來提供一個控制點,以解決這個問題。

                            同步記號(Synchronizer (or Dvu) Token

                         

          這個策略是為了解決重復的form提交問題。一個同步的記號被設置在一個用戶的Session中,并且包含在返回到客戶的每一個form中。當form被提交時,form中的同步標記就和Session中的同步標記作對比。在form首次提交的時候,這兩個標記應該是一樣的。如果標記不一樣,那么該form就會禁止提交,一個錯誤就會返回給用戶。在用戶提交一個form時,如果按下瀏覽器中的后退按鈕并嘗試重新提交同一個form時,標記就會出現不匹配的現象。

          另一方面,如果兩個標記值匹配,那么我們就可以確信整個流程是正確的。在這種情況下,Session中的標記值就會被修改為一個新的值,同時允許提交該form。                                   你也可以使用這個策略來控制對某些頁面的直接訪問,就好象上面資源保護中描述的一樣。例如,假設一個用戶將某個應用的頁面A收藏到收藏夾中,而頁面A只允許通過頁面B和C訪問。當用戶直接通過收藏夾來訪問頁面A,這時頁面的訪問順序就是不正確的,這樣同步標記將處在一個不同步的狀態,或者它根本就不存在。不論怎樣,訪問都被禁止了。                 e、做一個hidden框,名字自己定,提交后得到這個值放入session,提交前判斷session是否為空   解決方案:        1、后臺公共類中實現前臺的Form中自動生成兩個hidden文本功能,一個是作page是否重復提交判斷,并由系統自動附上關鍵值(如struts采用的方案);另一個作為button是否重復提交判斷(struts中好像沒有)。由后臺公共類實現界面兩個hidden text自動生成的好處在于公用性。        2、在basic filter中根據兩個hidden text值判斷是否為重復提交。        3、javascript中作一個公共方法,實現功能:如果需要判斷是否重復提交,就給第二個hidden text附上關鍵值,并使該功能不可用。 . 個人感想:我相信未來該功能一定會被服務器集成,而不再由開發人員進行編碼.

          ----------------------------------------示例代碼----------------------------------------------------

          第一,對于不支持POST的,可以簡單的使用如下代碼
          if ("POST".equals(request.getMethod())) ...{
            // 正常進行
          }else...{
            // 異常請求
            out.print("異常訪問");
            return;
          }
          如果是servlet, 可以將doGet方法直接返回,不進行處理就行了
          public void doGet(HttpServletRequest request, HttpServletResponse response) ...{
            return;
          }
          public void doPost(HttpServletRequest request, HttpServletResponse response) ...{
            // 正常進行操作
          }
          還可以采用特定的標志來區分,比如
          <form><input type="hidden" name="action" value="insert"/></form>
          程序里這樣判斷
          if ("POST".equals(request.getMethod()) && ("insert".equals(request.getParameter("action")))) ...{
            // 正常進行
          }else...{
            // 異常請求
            out.print("異常訪問");
            return;
          }
          第二,判斷提交的來源referer,代碼如下
          if ("POST".equals(request.getMethod())) ...{
            String referer = request.getHeader("referer");
            if (referer == null || !referer.startsWith("http://"+request.getServerName())) ...{
              // 非法來源
              return;
            }
            // 正常進行
          }else...{
            // 異常請求
            out.print("異常訪問");
            return;
          }
          第三 防止重復提交的hashCode
          在表單顯示頁面
            //生成一個formhash,算法可以自己定,不隨便重復就可以了
            String formhash = MD5.encode(Long.toString(new Date().getTime()));
            //讀取當前session里面的hashCode集合,此處使用了Set,方便判斷。
            Set<String> formhashSession = (Set<String>) session.getAttribute("formhashSession");
            if (formhashSession == null) ...{
              formhashSession = new HashSet<String>();
            }
            // 檢測重復問題
            while (formhashSession.contains(formhash)) ...{
              formhash = MD5.encode(Long.toString(new Date().getTime()));
            }
            // 保存到session里面
            formhashSession.add(formhash);
            // 保存
            session.setAttribute("formhashSession", formhashSession);
          表單里面增加如下字段
          <input type="hidden" name="formhash" id="formhash" value="<%=formhash%>" />
          在表單提交頁面進行如下處理
              // 拿到表單的formhash
              String formhash = upload.getParameter("formhash");
              // 拿到session里面的集合
              Set<String> formhashSession = (Set<String>) session.getAttribute("formhashSession");
              // 如果沒有,則是重復提交,或者非法提交
              if (formhashSession == null || !formhashSession.contains(formhash)) ...{
                out.println("請不要重復提交!");
                return;
              }
              // 下面進行其它的操作
              //
              // 最后,如果操作成功,從session里面把這個formhash 刪掉!
              // 以免用戶少填寫了某個字段,造成表單無法再次提交
              formhashSession.remove(formhash);
              session.setAttribute("formhashSession", formhashSession);

          posted on 2010-04-23 11:22 Todd 閱讀(3283) 評論(2)  編輯  收藏 所屬分類: 攻防

          評論

          # re: Java防止非法和重復表單提交 2013-09-16 15:42 33333333333333
          大廈大廈大廈大廈大廈大廈大廈大廈大廈  回復  更多評論
            

          # re: Java防止非法和重復表單提交 2013-09-16 15:43 33333333333333
          33333333333333  回復  更多評論
            

          主站蜘蛛池模板: 盐亭县| 淮滨县| 忻城县| 库尔勒市| 客服| 郸城县| 平定县| 大悟县| 佛学| 枞阳县| 常德市| 大新县| 大厂| 图木舒克市| 沙田区| 千阳县| 旬阳县| 乐至县| 石渠县| 清丰县| 南汇区| 和田县| 麻江县| 阜康市| 金沙县| 婺源县| 喀什市| 淮阳县| 吐鲁番市| 维西| 进贤县| 藁城市| 阳山县| 浪卡子县| 泸水县| 克什克腾旗| 丹棱县| 手游| 图木舒克市| 大冶市| 西安市|