امنیت در MVC با استفاده Anti-Forgery token (قسمت اول)

در این مقاله قصد داریم به توضیحی درباره امن بودن صفحات وب با استفاده از صفت Anti-Forgery token و نحوه پیاده سازی آن در وب فرم با تلکنولوژی MVC بپردازیم

امنیت در MVC  با استفاده Anti-Forgery token (قسمت اول)

شرح مختصری از مقاله :

1- طریقه پیاده سازی و برقراری امنیت در ASp و MVC

2-نحوه اعتبار سنجی سمت سرور به صورت Ajax

پیاده سازی در ASp.Web Form:

برای امنیت در صفحات وب و جلوگیری از حملات CSRF, یا XSRF به صورت زیر باید رفتار کنیم در واقع باید  یک توکن در کوکی ویک توکن داخل فرم ها تنطیم شده باشند.

و هنگامی که کاربر دکمه ثبت را انتخاب کرد توکن داخل کوکی و توکن داخل فرم ها به صورت http فرستاده میشوند و در آخر مورد تایید سرور باید قرار بگیرید.

برای ایجاد توکن یا نشانه (token) توسط مرورگر ها ، باید از HtmlHelper.AntiForgeryToken() در صفحه aspx ای که میخواهید امنیت آن را تضمین کنید یه صورت زیر استفاده کنید .

<% using (Html.BeginForm())
   { %> 
   <%: this.Html.AntiForgeryToken(Constants.AntiForgeryTokenSalt)%>
 
    <%-- Other fields. --%>
 
    <input type="submit" value="Submit" /><% } %>

 

پس از اجرا توکن تولید شده را به صورت زیر داخل فرم ها ایجاد میکنیم:

<form action="..." method="post">  
  <input name="
__RequestVerificationToken"
 type="hidden" 
value="J56khgCvbE3bVcsCSZkNVuH9Cclm9SSIT/ywruFsXEgmV8CL2eW5C/gGsQUf/YuP" />
 
    <!-- Other fields. -->
 
    <input type="submit" value="Submit" 
/></form>

 

و سپس نیز به صورت زیر داخل کوکی مینویسیم:

RequestVerificationToken_Lw__=
J56khgCvbE3bVcsCSZkNVuH9Cclm9SSIT/ywruFsXEgmV8CL2eW5C/gGsQUf/YuP

هنگامی که موارد بالا را در فرم نوشتیم هر دو آن ها به سمت سرور فرستاده میشوند که باعث برقراری امنیت میگردد.

برقراری امنیت در MVC:

در MVC برای برقراری امنیت از توکن ها به صورت صفت [ValidateAntiForgeryToken] استفاده میشوند

 و نحوه استفاده از این صفت در کنترلر بالای هر متد post  میباشد

[HttpPost][ValidateAntiForgeryToken(Salt = Constants.AntiForgeryTokenSalt)]
public ActionResult Action(/* ... */)
{ 
   // ...
}

 نحوه اعتبار سنجی برای کل کنترلر ( نه فقط متدهای Post ):

همان طور که در بالا گفته شد این صفت فقط برای متد های post (زیرا متد هایی هستند که سمت سرور ارسال میشوند ) استفاده میشود. حال در نظر بگیرید که یک  کنترلر شامل چندین متد post باشد و برای برقراری امنیت  باید بالای هر متد Post از این صفت استفاده کنیم که شاید کار حصوله سر بری باشد.

معمولا درکنترلرها متد ها هم شامل httpGet و هم شامل Httppost هستند و معمولا اعتبار سنجی ها سمت متد Post میباشد. امادر واقع مشکل اینجاست که اگر بخواهیم از صفت ValidateAntiForgeryToke  در بالای کنترلر استفاده کنیم این صفت از سمت متدهای Get نامعتبر شناخته میشوند.

[ValidateAntiForgeryToken(Salt = Constants.AntiForgeryTokenSalt)]
public class ProductController : Controller // One [ValidateAntiForgeryToken] attribute.
{
[HttpGet]  
public ActionResult Index() // Index() cannot work.
{ 
    // ...   
}
 
[HttpPost]
public ActionResult PostAction1(/* ... */)  
{  
       // ... 
}
 
HttpPost] 
public ActionResult PostAction2(/* ... */)   
{ 
       // ...  
}
 

اگر از کد بالا اجرا بگیرید با خطایی مانند زیر روبه رو مشوید:

tp://Site/Product/Index?__RequestVerificationToken=???

برای رفع این خطا کافی است فقط صفت ValidateAntiForgeryToken را در بالای هر متد Post اعمال کنیم:

public class ProductController : Controller // Many [ValidateAntiForgeryToken] attributes.
{ 
[HttpGet]
public ActionResult Index() // Works.
{   
     // ...  
}
 
[HttpPost]  
[ValidateAntiForgeryToken(Salt = Constants.AntiForgeryTokenSalt)]
public ActionResult PostAction1(/* ... */) 
{  
       // ...
}
[HttpPost]  
[ValidateAntiForgeryToken(Salt = Constants.AntiForgeryTokenSalt)] 
public ActionResult PostAction2(/* ... */)  
{  
      // ...  
}

 

حال برای رفع این مشکل به جای استفاده ازValidateAntiForgeryToken از یک فیلتر دیگری به

نام ValidateAntiForgeryTokenWrapperAttribut که به صورت دستی ایجاد کردیم استفاده میکنیم برای

استفاده از این فیلتر کافی است یک کلاس ایجاد کرده و کد های زیر را داخل آن بنویسیم:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateAntiForgeryTokenWrapperAttribute : FilterAttribute, IAuthorizationFilter
{  
  private readonly ValidateAntiForgeryTokenAttribute _validator;
  private readonly AcceptVerbsAttribute _verbs;
  public ValidateAntiForgeryTokenWrapperAttribute(HttpVerbs verbs)        : this(verbs, null) 
  {
  }
  public ValidateAntiForgeryTokenWrapperAttribute(HttpVerbs verbs, string salt)  
  { 
    this._verbs = new AcceptVerbsAttribute(verbs);  
    this._validator = new ValidateAntiForgeryTokenAttribute() 
        
  }
 
  public void OnAuthorization(AuthorizationContext filterContext) 
  {   
      string httpMethodOverride = filterContext.HttpContext.Request.GetHttpMethodOverride();  
      if (this._verbs.Verbs.Contains(httpMethodOverride, StringComparer.OrdinalIgnoreCase))  
      {    
        this._validator.OnAuthorization(filterContext);   
     }    
  }
}

و برای استفاده از این فیلتر در بالای هرکنترلر به صورت زیر رفتار میکنیم:

[ValidateAntiForgeryTokenWrapper(HttpVerbs.Post, ]
public class ProductController : Controller
{
    // GET actions are not affected.  
  // Only HTTP POST requests are validated.
}

 همان طور که مشاهد میکنید این صفت تمام متد های Post موجود در کنترلر را شامل میشود.