Asp.net-Mvc

是否可以/正確在一頁中以 2 種不同形式使用多個 @Html.AntiForgeryToken()?

  • November 14, 2015

我一直面臨著嚴重的問題@Html.AntiForgeryToken()。我有一個註冊控制器,它有一個創建視圖來創建/註冊新成員。出於這個原因,我@Html.AntiForgeryToken()在我的主要送出表單中使用了 a 而沒有使用任何 SALT。現在我想驗證使用者名是否已經存在於我的使用者名文本框的模糊事件的數據庫中。對於這個驗證,我編寫了一個名為“Validation”的新控制器,並編寫了一個帶有常量驗證 SALT 的方法:

[HttpPost]
   [ValidateAntiForgeryToken(Salt = @ApplicationEnvironment.SALT)]
   public ActionResult username(string log) {
       try {
           if (log == null || log.Length < 3)
               return Json(log, JsonRequestBehavior.AllowGet);

           var member = Membership.GetUser(log);

           if (member == null) {
               //string userPattern = @"^([a-zA-Z])[a-zA-Z_-]*[\w_-]*[\S]$|^([a-zA-Z])[0-9_-]*[\S]$|^[a-zA-Z]*[\S]$";
               string userPattern = "[A-Za-z][A-Za-z0-9._]{3,80}";
               if (Regex.IsMatch(log, userPattern))
                   return Json(log, JsonRequestBehavior.AllowGet);
           }

       } catch (Exception ex) {
           CustomErrorHandling.HandleErrorByEmail(ex, "Validate LogName()");
           return Json(log, JsonRequestBehavior.AllowGet);
       }
       //found e false
       return Json(log, JsonRequestBehavior.AllowGet);

   }

方法工作正常。我檢查了沒有的 HTTP Get 註釋[ValidateAntiForgeryToken],它給了我預期的結果。

我用Google搜尋並檢查了許多給定的解決方案,但這些都不起作用。對於我的驗證控制器,我在同一頁面中使用了另一個表單,並在防偽令牌中使用了 SALT。

範例:主送出表單的第一個防偽令牌:

@using (Html.BeginForm(“Create”, “Register”)) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) … }

第二個防偽令牌:

<form id="__AjaxAntiForgeryForm" action="#" method="post">
   @Html.AntiForgeryToken(SALT)
</form> 

在javascript中我使用了這個

<script type="text/javascript" defer="defer">
   $(function () {
       AddAntiForgeryToken = function (data) {
           data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
           return data;
       };

       if ($("#LogName").length > 0) {

           $("#LogName").blur(function () {
               var user = $("#LogName").val();
               var logValidate = "/Validation/username/";
               //var URL = logValidate + user;
               //var token = $('#validation input[name=__RequestVerificationToken]').val();
               data = AddAntiForgeryToken({ log: user });

               $.ajax({
                   type: "POST",
                   dataType: "JSON",
                   url: logValidate,
                   data: data,
                   success: function (response) {
                       alert(response);
                   }
               });

           });

       }
   });
</script>

在我的螢火蟲中,我得到了這個:

log=admin&__RequestVerificationToken=NO8Kds6B2e8bexBjesKlwkSexamsruZc4HeTnFOlYL4Iu6ia%2FyH7qBJcgHusekA50D7TVvYj%2FqB4eZp4VDFlfA6GN5gRz7PB%2ByZ0AxtxW4nT0E%2FvmYwn7Fvo4GzS2ZAhsGLyQC098dfIJaWCSiPcc%2FfD00FqKxjvnqmxhXvnEx2Ye83LbfqA%2F4XTBX8getBeodwUQNkcNi6ZtAJQZ79ySg%3D%3D

已通過,但在 cookie 部分中,我得到的 cookie 與傳遞的 cookie 不同:實際 Cookie:

ws5Dt2if6Hsah rW2nDly P3cW1smIdp1Vau 0TXOK1w0ctr0BCso/nbYu w9blq/QcrXxQLDLAlKBC3Tyhp5ECtK MxF4hhPpzoeByjROUG0NDJfCAlqVVwV5W6lw9ZFp/VBcQmwBCzBM/36UTBWmWn6pMM2bqnyoqXOK4aUZ4=

我認為這是因為我在一頁中使用了 2 個防偽令牌。但在我看來,我應該使用 2,因為第一個是為送出生成而下一個是需要驗證驗證。但是,這是我的猜測,我認為我錯了,因此我需要你們的幫助。

誰能解釋一下我應該使用兩個防偽還是一個?

謝謝大家….

最後8個小時的掙扎給了我一個解決方案。

首先,是的,在頁面中使用 2 個防偽令牌沒有害處。其次,無需將 cookie 與提供令牌匹配。提供令牌將始終不同,並將在伺服器中進行驗證。

如果我們使用動作動詞,則防偽令牌不起作用[HttpGet]..因為在防偽的驗證過程中,通過 Request.Form['__RequestVerificationToken']從請求中檢索值來驗證令牌。參考:史蒂文桑德森的部落格:防止交叉…

解決方案

我的修改控制器:

[HttpPost]

       [ValidateAntiForgeryToken(Salt = @ApplicationEnvironment.SALT)]
//change the map route values to accept this parameters.
       public ActionResult username(string id, string __RequestVerificationToken) {
       string returnParam = __RequestVerificationToken;

       try {
           if (id == null || id.Length < 3)
               return Json(returnParam, JsonRequestBehavior.AllowGet);

           var member = Membership.GetUser(id);

           if (member == null) {
               //string userPattern = @"^([a-zA-Z])[a-zA-Z_-]*[\w_-]*[\S]$|^([a-zA-Z])[0-9_-]*[\S]$|^[a-zA-Z]*[\S]$";
               string userPattern = "[A-Za-z][A-Za-z0-9._]{3,80}";
               if (Regex.IsMatch(id, userPattern))
                   return Json(returnParam, JsonRequestBehavior.AllowGet);
           }

       } catch (Exception ex) {
           CustomErrorHandling.HandleErrorByEmail(ex, "Validate LogName()");
           return Json(returnParam, JsonRequestBehavior.AllowGet);
       }
       //found e false
       return Json(returnParam, JsonRequestBehavior.AllowGet);
   }

我在同一頁面中的第一個表單:

@using (Html.BeginForm("Create", "Register")) {

   @Html.AntiForgeryToken(ApplicationEnvironment.SALT)

   @Html.ValidationSummary(true)
   ....
}

我在同一頁面中的第二個表格:

**<form id="validation">
   <!-- there is harm in using 2 anti-forgery tokens in one page-->
   @Html.AntiForgeryToken(ApplicationEnvironment.SALT)
   <input type="hidden" name="id" id="id" value="" />
</form>**

我的 jQuery 來解決這個問題:

$("#LogName").blur(function () {
           var user = $("#LogName").val();
           var logValidate = "/Validation/username/";
           $("#validation #id").val(user);
           **var form = $("#validation").serialize(); // a form is very important to verify anti-forgery token and data must be send in a form.**

           var token = $('input[name=__RequestVerificationToken]').val();

           $.ajax({
               **type: "POST", //method must be POST to validate anti-forgery token or else it won't work.**
               dataType: "JSON",
               url: logValidate,
               data: form,
               success: function (response) {
                   alert(response);
               }
           });
       });

引用自:https://stackoverflow.com/questions/12341725