2015-10-29 19 views
9
  1. Tôi muốn có dự án MVC về dự án WebAPI www.example1.com
  2. trên api.example2.com

Tôi muốn hạn chế quyền truy cập vào WebAPI. Tôi đã cố gắng triển khai Mã thông báo chống giả mạo:Làm cách nào để triển khai Mã thông báo chống giả mạo giữa giao diện người dùng MVC và Web Api trên các miền khác nhau?

Khi tôi tạo yêu cầu GET cho WebApi bằng mã thông báo Chống giả mạo thì tôi nhận được ngoại lệ vì yêu cầu không chứa mã thông báo này.

Trong phương pháp có tên ValidateRequestHeader là biến cookie = null.

Tôi làm cách nào để khắc phục mã sau? Đây có phải là giải pháp đúng không?

dự án MVC (front-end) - cho sự phát triển là localhost:33635:

Index.cshtml

<div class="container"> 


    <div class="row"> 

     <div class="col-md-12"> 


      <input id="get-request-button" type="button" class="btn btn-info" value="Create request to API Server" /> 

      <br /> 

      <div id="result"></div> 

     </div> 


    </div> 


</div> 


@section scripts 
{ 

    <script type="text/javascript"> 

     @functions{ 
      public string TokenHeaderValue() 
      { 
       string cookieToken, formToken; 
       AntiForgery.GetTokens(null, out cookieToken, out formToken); 
       return cookieToken + ":" + formToken; 
      } 
     } 

     $(function() { 

      $("#get-request-button").click(function() { 

       $.ajax("http://localhost:33887/api/values", { 
        type: "GET", 
        contentType: "application/json", 
        data: {}, 
        dataType: "json", 
        headers: { 
         'RequestVerificationToken': '@TokenHeaderValue()' 
        } 
       }).done(function (data) { 
        $("#result").html(data); 
       }); 

       return false; 
      }); 

     }); 


    </script> 

} 

dự án WebAPI - phát triển là localhost:33887:

WebApiConfig.cs

public static void Register(HttpConfiguration config) 
     { 
      // Web API configuration and services 

      config.EnableCors(new EnableCorsAttribute("http://localhost:33635", "*", "*")); 

      // Web API routes 
      config.MapHttpAttributeRoutes(); 

      config.Routes.MapHttpRoute(
        name: "DefaultApi", 
        routeTemplate: "api/{controller}/{id}", 
        defaults: new { id = RouteParameter.Optional } 
      ); 
     } 

ValidateHttpAntiForgeryTokenAttribute.cs:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] 
    public sealed class ValidateHttpAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter 
    { 
     public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) 
     { 
      var request = actionContext.Request; 

      try 
      { 
       if (IsAjaxRequest(request)) 
       { 
        ValidateRequestHeader(request); 
       } 
       else 
       { 
        AntiForgery.Validate(); 
       } 
      } 
      catch (Exception) 
      { 
       actionContext.Response = new HttpResponseMessage 
       { 
        StatusCode = HttpStatusCode.Forbidden, 
        RequestMessage = actionContext.ControllerContext.Request 
       }; 
       return FromResult(actionContext.Response); 
      } 
      return continuation(); 
     } 

     private Task<HttpResponseMessage> FromResult(HttpResponseMessage result) 
     { 
      var source = new TaskCompletionSource<HttpResponseMessage>(); 
      source.SetResult(result); 
      return source.Task; 
     } 

     private bool IsAjaxRequest(HttpRequestMessage request) 
     { 
      IEnumerable<string> xRequestedWithHeaders; 
      if (!request.Headers.TryGetValues("X-Requested-With", out xRequestedWithHeaders)) return false; 

      var headerValue = xRequestedWithHeaders.FirstOrDefault(); 

      return !String.IsNullOrEmpty(headerValue) && String.Equals(headerValue, "XMLHttpRequest", StringComparison.OrdinalIgnoreCase); 
     } 

     private void ValidateRequestHeader(HttpRequestMessage request) 
     { 
      var headers = request.Headers; 
      var cookie = headers 
        .GetCookies() 
        .Select(c => c[AntiForgeryConfig.CookieName]) 
        .FirstOrDefault(); 

      IEnumerable<string> xXsrfHeaders; 

      if (headers.TryGetValues("RequestVerificationToken", out xXsrfHeaders)) 
      { 
       var rvt = xXsrfHeaders.FirstOrDefault(); 

       if (cookie == null) 
       { 
        throw new InvalidOperationException($"Missing {AntiForgeryConfig.CookieName} cookie"); 
       } 

       AntiForgery.Validate(cookie.Value, rvt); 
      } 
      else 
      { 
       var headerBuilder = new StringBuilder(); 

       headerBuilder.AppendLine("Missing X-XSRF-Token HTTP header:"); 

       foreach (var header in headers) 
       { 
        headerBuilder.AppendFormat("- [{0}] = {1}", header.Key, header.Value); 
        headerBuilder.AppendLine(); 
       } 

       throw new InvalidOperationException(headerBuilder.ToString()); 
      } 
     } 
    } 

ValuesController:

public class ValuesController : ApiController 
    { 
     // GET: api/Values 
     [ValidateHttpAntiForgeryToken] 
     public IEnumerable<string> Get() 
     { 
      return new string[] { "value1", "value2" }; 
     } 

     // GET: api/Values/5 
     public string Get(int id) 
     { 
      return "value"; 
     } 

     // POST: api/Values 
     public void Post([FromBody]string value) 
     { 
     } 

     // PUT: api/Values/5 
     public void Put(int id, [FromBody]string value) 
     { 
     } 

     // DELETE: api/Values/5 
     public void Delete(int id) 
     { 
     } 
    } 
+0

@teovankot Tôi muốn giải quyết việc chia sẻ AntiForgeryToken giữa hai máy chủ. Liên kết của bạn được giải quyết chỉ Mã thông báo chống giả mạo trên một máy chủ. – Jenan

+0

Xin lỗi đó là điều xấu của tôi –

Trả lời

6

Đây không phải là cách để hạn chế khả năng tiếp cận bởi một dịch vụ. ForgeryToken giúp ngăn chặn các cuộc tấn công CSRF, ASP.NET MVC sử dụng mã thông báo chống giả mạo, còn được gọi là mã thông báo xác minh yêu cầu. Máy khách yêu cầu một trang HTML có chứa một biểu mẫu. Máy chủ bao gồm hai mã thông báo trong phản hồi. Một mã thông báo được gửi dưới dạng cookie. Khi bạn gửi biểu mẫu, các biểu mẫu đó sẽ khớp trên cùng một máy chủ.

Tôi tin rằng, Điều bạn cần là sự tin tưởng từ example1.com đến api.example2.com. An example sẽ là stackauth là miền dành cho các dịch vụ tập trung trên toàn bộ Stack Exchange network. Sau đó, bạn có thể thực hiện ủy quyền khi bạn cần trong dự án của mình.

+0

Ý của bạn là gì với "tin cậy fron example1.com và example2.com" - làm cách nào tôi có thể làm điều này? Cảm ơn bạn – Jenan

+0

Đó là logic mà bạn sử dụng bên trong các ứng dụng web của mình. Ví dụ xác thực và ủy quyền bởi một tên miền khác với các yêu cầu cụ thể được gửi bởi ứng dụng hiện tại. –

Các vấn đề liên quan