Skip to content

Latest commit

Β 

History

History
207 lines (144 loc) Β· 8.01 KB

CORS.md

File metadata and controls

207 lines (144 loc) Β· 8.01 KB

CORS

Cross-Origin Resource Sharing, CORS

λ‹€λ₯Έ 좜처의 μžμ›μ„ κ³΅μœ ν•  수 μžˆλ„λ‘ μ„€μ •ν•˜λŠ” κΆŒν•œ 체제

λΈŒλΌμš°μ €μ—μ„œλŠ” λ³΄μ•ˆμ μΈ 이유둜 cross-origin HTTP μš”μ²­λ“€μ„ μ œν•œν•œλ‹€. λ”°λΌμ„œ cross-origin μš”μ²­μ„ ν•˜λ €λ©΄ μ„œλ²„μ˜ λ™μ˜κ°€ ν•„μš”ν•˜λ‹€. λ§Œμ•½ μ„œλ²„κ°€ λ™μ˜ν•œλ‹€λ©΄ λΈŒλΌμš°μ €μ—μ„œλŠ” μš”μ²­μ„ ν—ˆλ½ν•˜κ³ , λ™μ˜ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ λΈŒλΌμš°μ €μ—μ„œ κ±°μ ˆν•œλ‹€.

κ·Έλž˜μ„œ λΈŒλΌμš°μ €μ—μ„œ cross-origin μš”μ²­μ„ μ•ˆμ „ν•˜κ²Œ ν•  수 μžˆλ„λ‘ ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ΄λ‹€.

λ”°λΌμ„œ CORSλ₯Ό 섀정해주지 μ•Šμ€ 경우, μ›ν•˜λŠ”λŒ€λ‘œ λ¦¬μ†ŒμŠ€λ₯Ό κ³΅μœ ν•˜μ§€ λͺ»ν•˜κ²Œ λœλ‹€.

cross-origin μ΄λž€

λ‹€μŒ 쀑 ν•œ 가지라도 λ‹€λ₯Έ 경우λ₯Ό λ§ν•œλ‹€.

  1. ν”„λ‘œν† μ½œ - http와 httpsλŠ” ν”„λ‘œν† μ½œμ΄ λ‹€λ₯΄λ‹€.
  2. 도메인 - domain.comκ³Ό other-domain.com 은 λ‹€λ₯΄λ‹€.
  3. 포트 번호 - 8080ν¬νŠΈμ™€ 3000ν¬νŠΈλŠ” λ‹€λ₯΄λ‹€.

CORSλŠ” μ™œ ν•„μš”ν•œκ°€?

CORSκ°€ 없이 λͺ¨λ“  κ³³μ—μ„œ 데이터λ₯Ό μš”μ²­ν•  수 있게 되면, λ‹€λ₯Έ μ‚¬μ΄νŠΈμ—μ„œ μ›λž˜ μ‚¬μ΄νŠΈλ₯Ό 흉내낼 수 있게 λœλ‹€.

e.g. κΈ°μ‘΄ μ‚¬μ΄νŠΈμ™€ μ™„μ „νžˆ λ™μΌν•˜κ²Œ λ™μž‘ν•˜λ„λ‘ ν•˜μ—¬ μ‚¬μš©μžκ°€ λ‘œκ·ΈμΈν•˜κ²Œ λ§Œλ“€κ³ , λ‘œκ·ΈμΈν•˜λ©΄ μ„Έμ…˜μ„ νƒˆμ·¨ν•˜μ—¬ μ•…μ˜μ μœΌλ‘œ 정보λ₯Ό μΆ”μΆœν•˜κ±°λ‚˜ λ‹€λ₯Έ μ‚¬λžŒμ˜ 정보λ₯Ό μž…λ ₯ν•˜λŠ” λ“± 곡격할 수 μžˆλ‹€.

λ”°λΌμ„œ μ΄λ ‡κ²Œ 곡격을 ν•  수 없도둝 λΈŒλΌμš°μ €μ—μ„œ λ³΄ν˜Έν•˜κ³ , ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ„œλ²„μ™€ ν˜‘μ˜ν•˜μ—¬ μš”μ²­ν•  수 μžˆλ„λ‘ ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•˜λ‹€.

CORSλŠ” μ–΄λ–»κ²Œ λ™μž‘ν•˜λŠ”κ°€?

Simple requests인 경우

  1. μ„œλ²„λ‘œ μš”μ²­μ„ ν•œλ‹€.
  2. μ„œλ²„μ˜ 응닡이 왔을 λ•Œ λΈŒλΌμš°μ €κ°€ μš”μ²­ν•œ Orgin κ³Ό 헀더 Access-Control-Request-Headers 의 값을 λΉ„κ΅ν•˜μ—¬ μœ νš¨ν•œ μš”μ²­μ΄λΌλ©΄ λ¦¬μ†ŒμŠ€λ₯Ό μ‘λ‹΅ν•œλ‹€. λ§Œμ•½ μœ νš¨ν•˜μ§€ μ•Šμ€ μš”μ²­μ΄λΌλ©΄ λΈŒλΌμš°μ €μ—μ„œ 이λ₯Ό 막고 μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

Simple requestλž€?

HTTP methodκ°€ λ‹€μŒ 쀑 ν•˜λ‚˜μ΄λ©΄μ„œ

  • GET
  • HEAD
  • POST

μžλ™μœΌλ‘œ μ„€μ •λ˜λŠ” ν—€λ”λŠ” μ œμ™Έν•˜κ³ , μ„€μ •ν•  수 μžˆλŠ” λ‹€μŒ ν—€λ”λ“€λ§Œ λ³€κ²½ν•˜λ©΄μ„œ

  • Accept
  • Accept-Language
  • Content-Language

Content-Type이 λ‹€μŒκ³Ό 같은 경우

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Simple request라고 λΆ€λ₯Έλ‹€. 이 μš”μ²­μ€ μΆ”κ°€μ μœΌλ‘œ ν™•μΈν•˜μ§€ μ•Šκ³  λ°”λ‘œ λ³Έ μš”μ²­μ„ 보낸닀.

preflight μš”μ²­μΌ 경우

  1. Origin 헀더에 ν˜„μž¬ μš”μ²­ν•˜λŠ” originκ³Ό, Access-Control-Request-Method 헀더에 μš”μ²­ν•˜λŠ” HTTP method와 Access-Control-Request-Headers μš”μ²­ μ‹œ μ‚¬μš©ν•  헀더λ₯Ό OPTIONS λ©”μ„œλ“œλ‘œ μ„œλ²„λ‘œ μš”μ²­ν•œλ‹€. μ΄λ•Œ λ‚΄μš©λ¬Όμ€ 없이 ν—€λ”λ§Œ μ „μ†‘ν•œλ‹€.
  2. λΈŒλΌμš°μ €κ°€ μ„œλ²„μ—μ„œ μ‘λ‹΅ν•œ 헀더λ₯Ό 보고 μœ νš¨ν•œ μš”μ²­μΈμ§€ ν™•μΈν•œλ‹€. λ§Œμ•½ μœ νš¨ν•˜μ§€ μ•Šμ€ μš”μ²­μ΄λΌλ©΄ μš”μ²­μ€ μ€‘λ‹¨λ˜κ³  μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. λ§Œμ•½ μœ νš¨ν•œ μš”μ²­μ΄λΌλ©΄ μ›λž˜ μš”μ²­μœΌλ‘œ λ³΄λ‚΄λ €λ˜ μš”μ²­μ„ λ‹€μ‹œ μš”μ²­ν•˜μ—¬ λ¦¬μ†ŒμŠ€λ₯Ό μ‘λ‹΅λ°›λŠ”λ‹€.

preflight μš”μ²­μ΄λž€?

Simple requestsκ°€ μ•„λ‹Œ cross-origin μš”μ²­μ€ λͺ¨λ‘ preflight μš”μ²­μ„ ν•˜κ²Œ λ˜λŠ”λ°, μ‹€μ œ μš”μ²­μ„ λ³΄λ‚΄λŠ” 것이 μ•ˆμ „ν•œμ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ λ¨Όμ € OPTIONS λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ cross-origin HTTP μš”μ²­μ„ 보낸닀. μ΄λ ‡κ²Œ ν•˜λŠ” μ΄μœ λŠ” μ‚¬μš©μž 데이터에 영ν–₯을 λ―ΈμΉ  수 μžˆλŠ” μš”μ²­μ΄λ―€λ‘œ 사전에 확인 ν›„ λ³Έ μš”μ²­μ„ 보낸닀.

μš”μ²­ 헀더 λͺ©λ‘

  • Origin
  • Access-Control-Request-Method
    • preflight μš”μ²­μ„ ν•  λ•Œ μ‹€μ œ μš”μ²­μ—μ„œ μ–΄λ–€ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  것인지 μ„œλ²„μ—κ²Œ μ•Œλ¦¬κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€.
  • Access-Control-Request-Headers
    • preflight μš”μ²­μ„ ν•  λ•Œ μ‹€μ œ μš”μ²­μ—μ„œ μ–΄λ–€ headerλ₯Ό μ‚¬μš©ν•  것인지 μ„œλ²„μ—κ²Œ μ•Œλ¦¬κΈ° μœ„ν•΄ μ‚¬μš©λœλ‹€.

응닡 헀더 λͺ©λ‘

  • Access-Control-Allow-Origin
    • λΈŒλΌμš°μ €κ°€ ν•΄λ‹Ή origin이 μžμ›μ— μ ‘κ·Όν•  수 μžˆλ„λ‘ ν—ˆμš©ν•œλ‹€.
  • Access-Control-Expose-Headers
    • λΈŒλΌμš°μ €κ°€ μ•‘μ„ΈμŠ€ν•  수 μžˆλŠ” μ„œλ²„ ν™”μ΄νŠΈλ¦¬μŠ€νŠΈ 헀더λ₯Ό ν—ˆμš©ν•œλ‹€.
  • Access-Control-Max-Age
    • μ–Όλ§ˆλ‚˜ μ˜€λž«λ™μ•ˆΒ preflightμš”μ²­μ΄ 캐싱 될 수 μžˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚Έλ‹€.
  • Access-Control-Allow-Credentials
    • Credentialsκ°€ true 일 λ•Œ μš”μ²­μ— λŒ€ν•œ 응닡이 λ…ΈμΆœλ  수 μžˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • preflightμš”μ²­μ— λŒ€ν•œ μ‘λ‹΅μ˜ μΌλΆ€λ‘œ μ‚¬μš©λ˜λŠ” 경우 μ‹€μ œ 자격 증λͺ…을 μ‚¬μš©ν•˜μ—¬ μ‹€μ œ μš”μ²­μ„ μˆ˜ν–‰ν•  수 μžˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • κ°„λ‹¨ν•œ GET μš”μ²­μ€Β preflightλ˜μ§€ μ•ŠμœΌλ―€λ‘œ 자격 증λͺ…이 μžˆλŠ” λ¦¬μ†ŒμŠ€λ₯Ό μš”μ²­ν•˜λ©΄ 헀더가 λ¦¬μ†ŒμŠ€μ™€ ν•¨κ»˜ λ°˜ν™˜λ˜μ§€ μ•ŠμœΌλ©΄ λΈŒλΌμš°μ €μ—μ„œ 응닡을 λ¬΄μ‹œν•˜κ³  μ›Ή μ½˜ν…μΈ λ‘œ λ°˜ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • Access-Control-Allow-Methods
    • preflight`μš”μ²­μ— λŒ€ν•œ λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ ν—ˆμš©λ˜λŠ” λ©”μ„œλ“œλ“€μ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
  • Access-Control-Allow-Headers
    • preflightμš”μ²­μ— λŒ€ν•œ λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ μ‹€μ œ μš”μ²­ μ‹œ μ‚¬μš©ν•  수 μžˆλŠ” HTTP 헀더λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

Spring Boot둜 CORS μ„€μ •ν•˜κΈ°

1. Configuration 으둜 ν•΄κ²°ν•˜κΈ°

Globalν•˜κ²Œ μ μš©ν•˜λŠ” λ°©λ²•μœΌλ‘œ, config νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€μ–΄μ€€λ‹€.

κ²½λ‘œλŠ” /src/main/java/{project}/config λ§Œλ“€μ–΄μ§„ config νŒ¨ν‚€μ§€ μ•ˆμ— WebConfig 클래슀λ₯Ό λ§Œλ“€μ–΄μ€€λ‹€.

1.1. addMapping

@Configuration
public class WebConfig implements WebMvcConfigurer {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**");
	}
}

registry.addMapping을 μ΄μš©ν•΄μ„œ CORS μ μš©ν•  URL νŒ¨ν„΄μ„ μ •μ˜ν•  수 μžˆλ‹€.

μœ„ 처럼 β€œ/**” μ™€μΌλ“œ μΉ΄λ“œλ₯Ό μ‚¬μš©ν•  μˆ˜λ„ μžˆλ‹€.

λ˜ν•œ Ant-style도 μ§€μ›ν•˜λ©° β€œ/somePath/**” μ΄λ ‡κ²Œ μ μš©ν•  μˆ˜λ„ μžˆλ‹€.

Default 값은 μ•„λž˜μ™€ κ°™λ‹€.

  • Allow all origins.
  • Allow β€œsimple” methods GET, HEAD and POST
  • Allow all headers
  • Set max age to 1800 seconds (30 minutes).

1.2. allowedOrigins

@Configuration
public class WebConfig implements WebMvcConfigurer {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**")
						.allowedOrigins("*");
	}
}

.allowedOrigins("http://localhost:8080", "http://localhost:8081"); // ν•œ λ²ˆμ— μ—¬λŸ¬ Methodλ₯Ό ν—ˆμš©

allowedOrigins λ©”μ†Œλ“œλ₯Ό μ΄μš©ν•΄μ„œ μžμ› 곡유λ₯Ό ν—ˆλ½ν•  Origin을 지정할 수 μžˆλ‹€.

β€œ*β€λ‘œ λͺ¨λ“  Origin을 ν—ˆλ½ν•  수 μžˆλ‹€.

1.3. allowedMethods

@Configuration
public class WebConfig implements WebMvcConfigurer {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**")
						.allowedOrigins("*")
						.allowedMethods("GET", "POST");
	}
}

allowedMethodsλ₯Ό μ΄μš©ν•΄μ„œ ν—ˆμš©ν•  HTTP methodλ₯Ό 지정

1.4. maxAge

@Configuration
public class WebConfig implements WebMvcConfigurer {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**")
						.allowedOrigins("*")
						.allowedMethods("GET", "POST")
						.maxAge(3000);
	}
}

maxAge λ©”μ†Œλ“œλ₯Ό μ΄μš©ν•΄μ„œ μ›ν•˜λŠ” μ‹œκ°„λ§ŒνΌ pre-flight λ¦¬ν€˜μŠ€νŠΈλ₯Ό 캐싱 ν•΄λ‘˜ 수 μžˆλ‹€.

2. Annotation μ΄μš©ν•˜κΈ°

Controller λ˜λŠ” λ©”μ†Œλ“œλ‹¨μ—μ„œ annotation을 톡해 μ μš©ν•˜λŠ” 방법

@RequestMapping("/somePath")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class SomeController {
}

@RestController
@RequestMapping("/somePath")
public class SomeController {

    @CrossOrigin(origins="*")
    @RequestMapping(value = "/{something}",method = RequestMethod.DELETE)
    public ResponseEntity<String> delete(@PathVariable Long reservationNo) throws Exception{
    }

}
  • CorssOrigin μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ globalν•˜κ²Œ μ„€μ •ν•˜λ˜ 것 κ³Ό 같이 ν—ˆμš©ν•  originsμ΄λ‚˜ methodsλ₯Ό 지정할 수 μžˆλ‹€.
  • origins, methods, maxAge, allowedHeadersλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

[ref]
https://hannut91.github.io/blogs/infra/cors
https://dev-pengun.tistory.com/entry/Spring-Boot-CORS-μ„€μ •ν•˜κΈ°