In depth explanation of. Net core cores Middleware

Time:2019-11-5

Homology policy and cross domain resource sharing

1. Homology strategy

Homology policy, which is a famous security policy proposed by Netscape. Now all browsers that support JavaScript will use this strategy. The so-called homology refers to the same domain name, protocol and port.

1.1, purpose

It is mainly to ensure the security of user information and prevent the website from stealing user data. If there is no homology strategy, this may happen. Users visit two websites a / B and log in to website A. website a will store cookies or tokens locally on the computer. When visiting website B, website B can access these local stored information. Website B can use the user’s cookies to log in to website a, so that the user information is leaked.

1.2 limitation

  • Cookies, localstorage, and indexdb are inaccessible (cookies can only be shared by pages of the same origin)
  • DOM cannot get (the address of the parent window and the child window are the same source to get the information of the child window)
  • Ajax requests cannot be sent (Ajax requests can only be sent to the same origin web address)

You should know that these restrictions are actually restrictions made by browsers.

2. Cross domain resource sharing

Cross domain resource sharing is the opposite of the same origin strategy. In the whole process of cross domain communication, the browser will automatically identify whether the request is cross domain. Once cross domain is found, it will automatically add request header information (such as origin) or automatically send a pre request with option as the request mode. The browser divides CORS requests into two categories: simple requests and non simple requests.

2.1 simple request

When the browser’s request mode is head, get or post, and the HTTP header information does not exceed the following fields:

  • Accept
  • Accept-Language
  • Content-Language
  • Origin

The browser defines the request as a simple request, otherwise it is a non simple request. When the browser judges that it is a simple request, the browser will automatically add the origin field to the request header, indicating the address (protocol + domain name + port) from which the request comes. Then the server needs to decide whether to accept the request from this source. If access control allow origin is required in the header allowed to be returned by the server, its value is the value of origin field at the time of request or * (indicating accepting the request from any source). There will also be access control allow methods in the request header to indicate how cross domain requests are allowed by the server. Access control allow headers represents the allowed fields in the request header.

2.2. Non simple request

When the browser judges that it is a non simple request, it will send two requests. First, the browser will automatically send a request with the request mode of options, and in the request header

  • Add access control request method to indicate the next request method,
  • Add origin to indicate source,
  • Add access control request headers to indicate additional fields in the next request header.

After receiving the request, the server needs to obtain the values in the three request headers, and make a judgment to confirm whether cross domain is allowed. If the request header returned by the server does not contain any CORS related request header information, the browser will consider that it does not pass the pre check and will not make a second request.

If the server accepts the cross domain request and validates the options request, it will return access control allow origin, access control allow methods and access control allow headers. Then the browser will send the real request.

                 

(first options request)

(second request)

2. The server implements CORS

Easy to use in. Net core web API, install the package firstMicrosoft.AspNet.WebApi.Cors, add the following two sentences to startup

public void ConfigureServices(IServiceCollection services)
 {
  services.AddMvc();
       //Add CORS and configure corspolicy 
  services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
 }

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
  if (env.IsDevelopment())
  {
  app.UseDeveloperExceptionPage();
  }// note that usecos() should be before usemvc()
  app.UseCors("CorsTest");
  app.UseMvc();
 }

When you use it, you only need to add features to the controller or action[EnableCors("CorsTest")]


[EnableCors("CorsTest")]
 public class ValuesController : Controller
 {
 private ILogger<ValuesController> _logger;
 public ValuesController(ILogger<ValuesController> logger)
 {
  _logger = logger;
 }
 [HttpGet]
 public IEnumerable<string> Get()
 {
  return new string[] { "value1", "value2" };
 }
 }

Now that the server has been configured, cross domain requests need to be made through the front end

<html>
<head>
 test
</head>
<body>
 test
</body>
</html>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
 $(function () {
 $.ajax({
  type: "get",
  url: "http://localhost:7000/api/values",
  BeforeSend: function (request) {// the purpose of adding authorization to the request header is to make the request non simple
  request.setRequestHeader("Authorization", "Bearer 071899A00D4D4C5B1C41A6B0211B9399");
  },
  success: function (result) {
  alert(result);
  }
 }, "json");
 });
</script>

The test results are as follows:

(options request)

(second request)

The above configuration allows all addresses to request this interface, or configure an address separately.


services.AddCors(options => options.AddPolicy("CorsTest", p => p.WithOrigins("http://localhost:8089")
                   .AllowAnyHeader()
                   .AllowAnyMethod()));

III. analysis of CORS source code

Open the CORS source code, mainly including corsmiddleware, corsoptions, corspolicy, corspolicybuilder, corsresult and corsservice.

  • Corspolicy: This is our configuration in startup. For example, which domain names are allowed to cross domain requests, which cross domain request methods are allowed, and which additional request headers are allowed. Each configuration corresponds to a name.
           services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
  • Corsoptions: contains a dictionaryIDictionary<string, CorsPolicy> PolicyMap, a project may have a CORS configuration, so the corsoptions manage these configurations by configuration name.
  • Corspolicybuilder: it is used to construct corspolicy.
  • Corsresult: is the result of validating cross domain processes. If the client sends the origin: http: / / localhost: 8089 in the first options request, the server will return access control allow origin: http: / / localhost: 8089. The server verifies whether the domain name http: / / localhost: 8089 allows cross domain. If it allows, the value “http: / / localhost: 8089” will be stored in the allowedheaders of corsresult. In the request (the first request) Add these to the HTTP request header when returning.
  • Corsmiddleware: the main method of CORS middleware class is invoke, which is called every HTTP request.
public async Task Invoke(HttpContext context)
  {// judge whether the HTTP request header has origin, and then judge whether it is a cross domain request
   if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
   {
    var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
    if (corsPolicy != null)
    {
     Var accesscontrolrequestmethod = context. Request. Headers [corsconstants. Accesscontrolrequestmethod]; // if it is a cross domain request, judge whether it is the first options request
     if (string.Equals(context.Request.Method,CorsConstants.PreflightHttpMethod,StringComparison.OrdinalIgnoreCase) 
      &&!StringValues.IsNullOrEmpty(accessControlRequestMethod))
     {// judge whether the current request is allowed to cross domains. Get the corsresult according to the content of httpcontext and the CORS configuration, and then add the content of corsresult to the request header (see details below)
      ApplyCorsHeaders(context, corsPolicy);
      context.Response.StatusCode = StatusCodes.Status204NoContent;
      return;
     }
     else
     {// perform the second non options request
      context.Response.OnStarting(state =>
      {
       var (httpContext, policy) = (Tuple<HttpContext, CorsPolicy>)state;
       try
       {
        ApplyCorsHeaders(httpContext, policy);
       }
       catch (Exception exception)
       {
        _logger.FailedToSetCorsHeaders(exception);
       }
       return Task.CompletedTask;
      }, Tuple.Create(context, corsPolicy));
     }
    }
   }
   await _next(context);
  }
    
  private void ApplyCorsHeaders(HttpContext context, CorsPolicy corsPolicy)
  {// the corsresult is obtained through the data requested by the HTTP context and the CORS configuration. For example, when the first options request is made, the client sends the origin: http: // localhost: 8089, access control request methods: get server will return access control allow origin: http: // localhost: 8089, access control allow methods: get The server verifies whether the domain name http: // localhost: 8089 allows cross domain by get request. If it allows, store the value "http: // localhost: 8089" in allowedheaders of corsresult and "get" in allowedmethods of corsresult
   Var corsresult = ﹤ corsservice. Evaluatepolicy (context, corspolicy); // add the value in corsresult to the corresponding header and return it to the client
   _corsService.ApplyResult(corsResult, context.Response);
  }

The source code of CORS is relatively simple and easy to understand. You can write a project by yourself, and then hang the source code step-by-step debugging.

summary

The above is the whole content of this article. I hope that the content of this article has a certain reference learning value for everyone’s study or work. If you have any questions, you can leave a message and exchange. Thank you for your support for developepaar.