Skip to main content

CORS和在Spring Framework裡的應用

Updated 2 min readMarkdown

Intro

Cross-Origin Resource Sharing (CORS) MDN Spec

為了防止XSS Attack,也就是惡意的JS讓使用者發請求到第三方網站,瀏覽器會限制XHR Request只能發到同一個origin。CORS Header讓伺服器端可以設定允許的origin。

Specifications

Simple Request & Preflight Request

Simple Request: GET, HEAD, POST with Origin Header Preflight: OPTIONS with specific headers request before real request.

Preflight Request Headers

  • Access-Control-Request-Method : Specify the coming request method
  • Access-Control-Request-Headers:

CORS respose headers

- Access-Control-Allow-Origin : **main header concerned**
  • Access-Control-Allow-Credentials: Is credentials allowed (cookies..etc)
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers: which HTTP headers can be used during the actual request.
  • Access-Control-Max-Age
  • Access-Control-Expose-Headers: response header allows a server to indicate which response headers should be made available to scripts running in the browser

Fetch Metadata Request Header

sec-fetch-mode will be cors .

https://developer.mozilla.org/en-US/docs/Glossary/Fetch_metadata_request_header

  • 瀏覽器在fetch時會提供metadata,讓Server知道是怎麼樣的請求,比如說是XHR還是直接的request

  • Sec-Fetch-Site

    • cross-site: different domain
    • same-origin: same origin
    • same-site: same subdomain (e.g. sub.example.com and example.com)
    • none: user triggered request (directly in URL bar, bookmark, other application ..etc)
  • Sec-Fetch-Mode
    • cors: [[CORS]] request
    • navigate: normal navigation between HTML documents
    • no-cors
    • same-origin
    • websocket
  • Sec-Fetch-User
    • Always ?1 if the request is initiated by user.
  • Sec-Fetch-Dest
    • In what element will be used e.g. audio, image, iframe, document ..etc

Use curl to send CORS requests

Normal request

$ curl -X GET -H "Origin: https://example.com" https://foo.com/aaabbcc

Preflight request

$ curl -X OPTIONS -H "Access-Control-Request-Method: GET" -H "Origin: https://example.com" https://foo.bar/api/

Send CORS in browser

Open console tab in development mode and use fetch(url)

Spring Boot / Spring Framework

Ref links:

  • https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-cors
  • https://spring.io/guides/gs/rest-service-cors/
  • https://blog.csdn.net/f641385712/article/details/101036506
  • https://www.cnblogs.com/leftthen/p/6378090.html

Implementation

https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/cors/DefaultCorsProcessor.java

Support Preflight Requests

OPTIONS request is by default supported https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-requestmapping-head-options

By default, HTTP OPTIONS is handled by setting the `Allow` response header to the list of HTTP methods listed in all `@RequestMapping` methods that have matching URL patterns.

### @CrossOrigin Annotation
https://docs.spring.io/spring-framework/docs/5.3.14/javadoc-api/org/springframework/web/bind/annotation/CrossOrigin.html

Applying to a controller method
Main options: origins, originPatterns(>= 5.3), methods

Java Configuration

Global config in [[Spring Framework]]

package ...;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**").allowedOrigins("https://example.com");
            }
        };
    }
}
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/CorsRegistry.html#addMapping-java.lang.String-
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/CorsRegistration.html#allowedOrigins-java.lang.String...-

note: can't use wildcard in allowedOrigins. Only allowedOriginPatterns.

-https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/CorsRegistry.html

Detailed settings for CORS:

registry.addMapping("url") // -> returns  CorsRegistration
registry.addMapping("url").allowedOrigins(...).allowedHeaders(...).allowCredentials(...)

registry.addMapping("url").allowOriginPatterns() // Spring >= 5.3
  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/CorsRegistration.html

AWS Cloudfront

https://aws.amazon.com/premiumsupport/knowledge-center/no-access-control-allow-origin-error/

If CORS related headers are wrongly cached, the behavior would be strange.

Solutions:

  1. Add CORS related headers to cache key
  2. Use origin request policy
  3. Use managed origin request policy

No comments yet. Be the first to comment.

More from this blog