Todd

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            65 隨筆 :: 0 文章 :: 24 評(píng)論 :: 0 Trackbacks
          <2010年4月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          常用鏈接

          留言簿

          隨筆分類(71)

          隨筆檔案(61)

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          真是一切都逃不過(guò)session,看了DZ的formhash;struts token什么啊,就是個(gè)session,安全級(jí)別比驗(yàn)證碼還低。
          看看別人的分析有益身心啊,看之,目前來(lái)講一切都逃不過(guò)session


          預(yù)期達(dá)到目標(biāo)
          :

                 1、當(dāng)用戶進(jìn)行的是Refresh/Reload/Back/Forward操作、以及先BackSubmit操作時(shí),僅僅是reloading先前的結(jié)果頁(yè)。

                 2、當(dāng)用戶重復(fù)提交同一個(gè)任務(wù)操作時(shí),后臺(tái)服務(wù)接收并處理第一次提交的任務(wù),后面提交不起作用(不轉(zhuǎn)向也不提示)。

                 3、該功能具有公用性。

          基本形成思路:

                 1、在basic filter中實(shí)現(xiàn)公用性

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

                                   ...

                                   chain.doFilter(request,response);

                          }else{

                                   //問(wèn)題2:如何實(shí)現(xiàn)不轉(zhuǎn)向、不提示也不顯示空白頁(yè)

                          }

                 2、網(wǎng)上資料概括

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

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

                                   var flag=true;

                                   function checkForm(){

                                             if (flag==false){

                                                      return;

                                             }

                                  

                                             flag=false;

                                             document.form1.submit();

                                  

                                   }

                          cstruts webwork沒(méi)有找到這個(gè)資料)

                                   //驗(yàn)證事務(wù)控制令牌,<html:form >會(huì)自動(dòng)根據(jù)session中標(biāo)識(shí)生成一個(gè)隱含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有這樣的一個(gè)方法生成令牌華

                                      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、用戶使用瀏覽器時(shí),可以經(jīng)常使用向后的按鈕,因此就有可能重復(fù)提交一個(gè)他們已經(jīng)提交過(guò)的form,這樣就會(huì)帶來(lái)一個(gè)重復(fù)事務(wù)處理的問(wèn)題。同樣,一個(gè)用戶也可能在接收到一個(gè)確認(rèn)的頁(yè)面之前按下停止的按鈕,接著再次提交同一個(gè)form。對(duì)于這些情況,我們都想跟蹤并且禁止這些重復(fù)的提交,我們可以使用一個(gè)控制servlet來(lái)提供一個(gè)控制點(diǎn),以解決這個(gè)問(wèn)題。

                            同步記號(hào)(Synchronizer (or Dvu) Token

                         

          這個(gè)策略是為了解決重復(fù)的form提交問(wèn)題。一個(gè)同步的記號(hào)被設(shè)置在一個(gè)用戶的Session中,并且包含在返回到客戶的每一個(gè)form中。當(dāng)form被提交時(shí),form中的同步標(biāo)記就和Session中的同步標(biāo)記作對(duì)比。在form首次提交的時(shí)候,這兩個(gè)標(biāo)記應(yīng)該是一樣的。如果標(biāo)記不一樣,那么該form就會(huì)禁止提交,一個(gè)錯(cuò)誤就會(huì)返回給用戶。在用戶提交一個(gè)form時(shí),如果按下瀏覽器中的后退按鈕并嘗試重新提交同一個(gè)form時(shí),標(biāo)記就會(huì)出現(xiàn)不匹配的現(xiàn)象。

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

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

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

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

          評(píng)論

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

          # re: Java防止非法和重復(fù)表單提交 2013-09-16 15:43 33333333333333
          33333333333333  回復(fù)  更多評(píng)論
            

          主站蜘蛛池模板: 洪湖市| 江华| 忻城县| 锡林郭勒盟| 葫芦岛市| 文化| 新干县| 周至县| 靖边县| 张家川| 中阳县| 体育| 班玛县| 昌宁县| 廊坊市| 黑龙江省| 嵊泗县| 车险| 民勤县| 云浮市| 延川县| 盘山县| 临高县| 苏尼特左旗| 丰台区| 保康县| 潼关县| 山阴县| 那坡县| 海兴县| 钟祥市| 乐业县| 清镇市| 乌拉特后旗| 南投县| 库车县| 丰原市| 镇安县| 佛坪县| 万州区| 徐汇区|