2 ๋ถ„ ์†Œ์š”

๊ฐœ๋… ์„ค๋ช… ๋ฐ API

CORS(Cross-Origin Resource Sharing, ๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ )

  • HTTP ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ํ•œ ์ถœ์ฒ˜์—์„œ ์‹คํ–‰ ์ค‘์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ์„ ํƒํ•œ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋„๋ก ๋ธŒ๋ผ์šฐ์ €์— ์•Œ๋ ค์ฃผ๋Š” ์ฒด์ œ
  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฆฌ์†Œ์Šค๊ฐ€ ์ž์‹ ์˜ ์ถœ์ฒ˜์™€ ๋‹ค๋ฅผ ๋•Œ ๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ ํ—ค๋”์— Origin ํ•„๋“œ์— ์š”์ฒญ ์ถœ์ฒ˜๋ฅผ ํ•จ๊ป˜ ๋‹ด์•„ ๊ต์ฐจ ์ถœ์ฒ˜ HTTP ์š”์ฒญ์„ ์‹คํ–‰ํ•œ๋‹ค.
  • ์ถœ์ฒ˜๋ฅผ ๋น„๊ตํ•˜๋Š” ๋กœ์ง์€ ์„œ๋ฒ„์— ๊ตฌํ˜„๋œ ์ŠคํŽ™์ด ์•„๋‹Œ ๋ธŒ๋ผ์šฐ์ €์— ๊ตฌํ˜„๋œ ์ŠคํŽ™ ๊ธฐ์ค€์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋ฉฐ ๋ธŒ๋ผ์šฐ์ €๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ ํ—ค๋”์™€ ์„œ๋ฒ„์˜ ์‘๋‹ตํ—ค๋”๋ฅผ ๋น„๊ตํ•ด์„œ ์ตœ์ข… ์‘๋‹ต์„ ๊ฒฐ์ •ํ•œ๋‹ค.
  • ๋‘๊ฐœ์˜ ์ถœ์ฒ˜๋ฅผ ๋น„๊ตํ•˜๋Š” ๋ฐฉ๋ฒ•์€ URL์˜ ๊ตฌ์„ฑ์š”์†Œ ์ค‘ Protocol, Host, Port ์ด ์„ธ๊ฐ€์ง€๊ฐ€ ๋™์ผํ•œ์ง€ ํ™•์ธํ•˜๋ฉด ๋˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ํ‹€๋ ค๋„ ์ƒ๊ด€์—†๋‹ค.

image

  • https://domain-a.com ์˜ ํ”„๋ก ํŠธ ์—”๋“œ JavaScript ์ฝ”๋“œ๊ฐ€ XMLHttpRequest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ https://domain-b.com/data.json์„ ์š”์ฒญํ•˜๋Š” ๊ฒฝ์šฐ ๋ณด์•ˆ ์ƒ์˜ ์ด์œ ๋กœ, ๋ธŒ๋ผ์šฐ์ €๋Š” ์Šคํฌ๋ฆฝํŠธ์—์„œ ์‹œ์ž‘ํ•œ ๊ต์ฐจ ์ถœ์ฒ˜ HTTP ์š”์ฒญ์„ ์ œํ•œํ•œ๋‹ค. image
  • XMLHttpRequest์™€ Fetch API๋Š” ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์„ ๋”ฐ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ด API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ž์‹ ์˜ ์ถœ์ฒ˜์™€ ๋™์ผํ•œ ๋ฆฌ์†Œ์Šค๋งŒ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋ ค๋ฉด ๊ทธ ์ถœ์ฒ˜์—์„œ ์˜ฌ๋ฐ”๋ฅธ CORS ํ—ค๋”๋ฅผ ํฌํ•จํ•œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ด์•ผํ•œ๋‹ค.

๋™์ผ ์ถœ์ฒ˜ ๊ธฐ์ค€

image

CORS ํ•ด๊ฒฐ - ์„œ๋ฒ„์—์„œ Access-Control-Allow-* ์„ธํŒ…

  • Access-Control-Allow-Origin - ํ—ค๋”์— ์ž‘์„ฑ๋œ ์ถœ์ฒ˜๋งŒ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฆฌ์†Œ์Šค๋ฅผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•œ๋‹ค
    • *, https://security.io
  • Access-Control-Allow-Methods - preflight request ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์‹ค์ œ ์š”์ฒญ ์ค‘์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค
    • ๊ธฐ๋ณธ๊ฐ’์€ GET,POST,HEAD,OPTIONS, *
  • Access-Control-Allow-Headers - preflight request ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์‹ค์ œ ์š”์ฒญ ์ค‘์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ—ค๋” ํ•„๋“œ ์ด๋ฆ„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค
    • ๊ธฐ๋ณธ๊ฐ’์€ Origin,Accept,X-Requested-With,Content-Type, Access-Control-Request-Method,Access-Control-Request-Headers, Custom Header, *
  • Access-Control-Allow-Credentials - ์‹ค์ œ ์š”์ฒญ์— ์ฟ ํ‚ค๋‚˜ ์ธ์ฆ ๋“ฑ์˜ ์‚ฌ์šฉ์ž ์ž๊ฒฉ ์ฆ๋ช…์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. Client์˜ credentials:include ์ผ๊ฒฝ์šฐ true ํ•„์ˆ˜
  • Access-Control-Max-Age - preflight ์š”์ฒญ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๋‹น ์‹œ๊ฐ„๋™์•ˆ์€ preflight์š”์ฒญ์„ ๋‹ค์‹œ ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค

CorsConfigurer

  • Spring Security ํ•„ํ„ฐ ์ฒด์ธ์— CorsFilter๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • corsFilter ๋ผ๋Š” ์ด๋ฆ„์˜ Bean์ด ์ œ๊ณต๋˜๋ฉด ํ•ด๋‹น CorsFilter๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค
  • corsFilter ๋ผ๋Š” ์ด๋ฆ„์˜ Bean์ด ์—†๊ณ  CorsConfigurationSource ๋นˆ์ด ์ •์˜๋œ ๊ฒฝ์šฐ ํ•ด๋‹น CorsConfiguration์ด ์‚ฌ์šฉ๋œ๋‹ค.
  • CorsConfigurationSource ๋นˆ์ด ์ •์˜๋˜์–ด ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ Spring MVC๊ฐ€ ํด๋ž˜์Šค ๊ฒฝ๋กœ์— ์žˆ์œผ๋ฉด HandlerMappingIntrospector๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค.

CorsFilter

  • CORS ์˜ˆ๋น„ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  CORS ๋‹จ์ˆœ ๋ฐ ๋ณธ ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๊ณ , ์ œ๊ณต๋œ CorsConfigurationSource ๋ฅผ ํ†ตํ•ด ์ผ์น˜๋œ ์ •์ฑ…์— ๋”ฐ๋ผ CORS ์‘๋‹ต ํ—ค๋”์™€ ๊ฐ™์€ ์‘๋‹ต์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•œ ํ•„ํ„ฐ์ด๋‹ค
  • Spring MVC Java ๊ตฌ์„ฑ๊ณผ Spring MVC XML ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ CORS๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋Œ€์•ˆ์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค ( ์˜ˆ: @CorsOrigin)
  • ์Šคํ”„๋ง ์›น์— ์˜์กดํ•˜๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ javax.servlet ์—์„œ CORS ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๋ณด์•ˆ ์ œ์•ฝ ์กฐ๊ฑด์— ์œ ์šฉํ•œ ํ•„ํ„ฐ์ด๋‹ค


@Override
protected void configure(final HttpSecurity http) throws Exception {
	http
		.authorizeRequests()
		.anyRequest().authenticated()
		.and();

    http.cors().configurationSource(corsConfigurationSource()); // CorsConfigurer ์„ค์ •์„ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค

}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();

    configuration.addAllowedOrigin("*");
    configuration.addAllowedMethod("*");
    configuration.addAllowedHeader("*");
    configuration.setAllowCredentials(true);
    configuration.setMaxAge(3600L);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);

    return source;

}


CORS ์š”์ฒญ์˜ ์ข…๋ฅ˜

Simple Request

  • Simple Request ๋Š” ์˜ˆ๋น„ ์š”์ฒญ(Prefilght)์„ ๊ณผ์ • ์—†์ด ๋ฐ”๋กœ ์„œ๋ฒ„์— ๋ณธ ์š”์ฒญ์„ ํ•œ ํ›„, ์„œ๋ฒ„๊ฐ€ ์‘๋‹ต์˜ ํ—ค๋”์— Access-Control-Allow-Origin ๊ณผ ๊ฐ™์€ ๊ฐ’์„ ์ „์†กํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์„œ๋กœ ๋น„๊ต ํ›„ CORS ์ •์ฑ… ์œ„๋ฐ˜์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค
  • ์ œ์•ฝ์‚ฌํ•ญ
    • GET, POST, HEAD ์ค‘์˜ ํ•œ๊ฐ€์ง€ Method๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค
    • ํ—ค๋”๋Š” Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width Width ๋งŒ ๊ฐ€๋Šฅํ•˜๊ณ  Custom Header ๋Š” ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค
    • Content-type ์€ application/x-www-form-urlencoded, multipart/form-data, text/plain ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค

image

Preflight Request (์˜ˆ๋น„์š”์ฒญ)

  • ๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ์„ ํ•œ๋ฒˆ์— ๋ณด๋‚ด์ง€ ์•Š๊ณ , ์˜ˆ๋น„์š”์ฒญ๊ณผ ๋ณธ์š”์ฒญ์œผ๋กœ ๋‚˜๋ˆ„์–ด ์„œ๋ฒ„์— ์ „๋‹ฌํ•˜๋Š”๋ฐ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์˜ˆ๋น„์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ Preflight ๋ผ๊ณ  ํ•˜๋ฉฐ ์ด ์˜ˆ๋น„์š”์ฒญ์˜ ๋ฉ”์†Œ๋“œ์—๋Š” OPTIONS ๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค
  • ์˜ˆ๋น„์š”์ฒญ์˜ ์—ญํ• ์€ ๋ณธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ๋ธŒ๋ผ์šฐ์ € ์Šค์Šค๋กœ ์•ˆ์ „ํ•œ ์š”์ฒญ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์š”์ฒญ ์‚ฌ์–‘์ด Simple Request ์— ํ•ด๋‹นํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ Preflight Request ์„ ์‹คํ–‰ํ•œ๋‹ค

image

RequestHeader ์˜ˆ์‹œ

image

  • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ณด๋‚ธ ์š”์ฒญ์„ ๋ณด๋ฉด Origin์— ๋Œ€ํ•œ ์ •๋ณด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์˜ˆ๋น„ ์š”์ฒญ ์ดํ›„์— ์ „์†กํ•  ๋ณธ ์š”์ฒญ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์ •๋ณด๋“ค๋„ ํ•จ๊ป˜ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • ์ด ์˜ˆ๋น„ ์š”์ฒญ์—์„œ ๋ธŒ๋ผ์šฐ์ €๋Š” Access-Control-Request-Headers ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ์ด ๋ณธ ์š”์ฒญ์—์„œ Content-Type ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ์•Œ๋ ค์ฃผ๊ฑฐ๋‚˜, Access-Control-Request-Method๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ GET ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ์„œ๋ฒ„์—๊ฒŒ ๋ฏธ๋ฆฌ ์•Œ๋ ค์ฃผ๊ณ  ์žˆ๋‹ค

Response Header ์˜ˆ์‹œ

image

  • ์„œ๋ฒ„๊ฐ€ ๋ณด๋‚ด์ค€ ์‘๋‹ต ํ—ค๋”์— ํฌํ•จ๋œ Access-Control-Allow-Origin: https://security.io ์˜ ์˜๋ฏธ๋Š” ํ•ด๋‹น URL ์™ธ์˜ ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ ์š”์ฒญํ•  ๊ฒฝ์šฐ์—๋Š” CORS ์ •์ฑ…์„ ์œ„๋ฐ˜ํ–ˆ๋‹ค๊ณ  ํŒ๋‹จํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฒ„๋ฆฌ๊ฒŒ ๋œ๋‹ค

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ:

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ