2023 12 04
2023-12-04¶
CORS¶
참고: https://www.youtube.com/watch?v=-2TgkKYmJt4 참고: https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F#%F0%9F%A4%94_%EA%B7%B8%EB%9F%BC_%EC%A3%84%EB%8B%A4_%EC%B0%A8%EB%8B%A8%ED%95%98%EB%A9%B4_%EC%9D%B8%ED%84%B0%EB%84%B7%EC%9D%B4_%EB%90%98%EB%8A%94%EA%B0%80?
- 개요
- 교차 출처 리소스 공유(CORS)는 추가 HTTP 헤더를 사용하여
- 한 출처에서 실행중인 웹 어플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제
- 같은 출처란?
- Protocol, Host, Port 가 다 같아야함
- 여기서 host는 string으로 비교해서 localhost와 127.0.0.1 은 다른놈임
- Protocol, Host, Port 가 다 같아야함
-
접근 제어 시나리오 [Preflight]
- 개요
- 사전확인 작업 (Options)
- Client <-> Server
- Preflight Request
- Origin: 요청 출처
- Access-Control-Request-Method: 실제 요청의 메서드
- Access-Control-Request-Headers: 실제 요청의 추가 헤더
- Preflight Response
- Access-Control-Allow-Origin: 서버 측 허가 출처
- Access-Control-Allow-Methods: 서버 측 허가 메서드
- Access-Control-Allow-Headers: 서버 측 허가 헤더
- Access-Control-Max-Age: Preflight 응답 캐시 기간 (브라우저야 캐싱해둬)
- 특징
- 응답 코드는 200대일 것
- 응답 바디는 비어있을 것
- 개요
- 접근 제어 시나리오 [Simple Request]
- Preflight 요청 없이 바로 요청을 날림
- 다음 조건을 모두 만족해야 Simple Request로 쓸 수 있음
- GET/POST/HEAD 메서드일 것
- Content-type은 하기의 작성된 것 중 하나일 것
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- Header는 하기의 작성된 것 중 하나일 것
- Accept
- Accept-Language
- Content-Language
- Content-Type
- 접근 제어 시나리오 [Credentialed Request]
- 인증 관련 헤더를 포함할 때 사용하는 요청
- 클라이언트 측
credentials: inclued
- 서버 측
Access-Control-Allow-Credentials: true
- 해결책 => 결국 CORS 해결책은 서버의 허용이 필요!
- CORS 동작 과정을 살펴보면... 결국
Access-Control-Allow-Origin헤더에 허용할 출처를 기재해서 클라이언트에게 응답 - 그러면 이제 클라이언트에서
Origin과 서버가 보내준Access-Control-Allow-Origin을 비교해서 차단할지 말지를 결정
- CORS 동작 과정을 살펴보면... 결국
- fetch API를 의심했었는데...
- 어이. fetch는 믿어라.
- 사실 CORS는 브라우저 정책이지, 서버끼리는 일어나지도 않고 그래.
- 브라우저가 Origin 비교해서 야 꺼져 하는거란 말이야?
- fetch도 post 쏘면 preflight 뚝딱 먼저 보낸다.
Play Framework에서 CORS¶
참고: https://www.playframework.com/documentation/2.8.x/CorsFilter#Enabling-the-CORS-filter 참고: https://www.playframework.com/documentation/2.8.x/resources/confs/filters-helpers/reference.conf 참고: https://coderunch.wordpress.com/2016/05/09/first-blog-post/ 참고: https://discuss.lightbend.com/t/cors-and-preflight-calls/225/10 참고: https://matthew.kr/%EA%B0%9C%EB%B0%9C%EC%9D%BC%EC%A7%80-play-framework-2-4-angularjs-%EA%B0%84%EC%97%90-cors-%ED%95%84%ED%84%B0-%ED%97%88%EC%9A%A9%ED%95%98%EA%B8%B0/
- 공식문서
- Filter를 기반으로 CORSFilter를 활성화하려고 했는데... 아무리해도 안먹힘 (진짜 삽질 너무함)
- 결국 CORS의 해결방법은 서버에서 http 헤더 적당한거 내려주는거야
- 그러면 Action에서 내려주자.
- 스프링으로 따지면 Interceptor에서 Response 처리해주는 역할
override def invokeBlock[A](request: Request[A], block: Request[A] => Future[Result]): Future[Result] = { block(request).map { result => result.withHeaders( HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN -> request.headers.get("Origin").getOrElse("*"), HeaderNames.ACCESS_CONTROL_ALLOW_METHODS -> "POST, GET, OPTIONS", HeaderNames.ACCESS_CONTROL_ALLOW_HEADERS -> "Origin, X-Requested-With, Content-Type, Accept, Referer, User-Agent", HeaderNames.ACCESS_CONTROL_MAX_AGE -> Integer.toString(60 * 60 * 24) ) } }