먼저 용어정리.
- SOP (Same Origin Policy) : 다른 출처의 리소스를 사용하는 것에 제한 하는 보안 방식
- 그럼 출처란 무엇일까? Protocol, Host , Port , Path , Query String, Fragment 등 URI에만 해도 많은 것들이 들어있다.
- 여기서 Protocol, Host, Port를 통해 같은 출처인지 다른 출처인지 판단이 가능하다. 무엇이라도 하나가 다르면 다른 출처라고 판단하게 된다.
- 브라우저는 hots를 string value를 통해 비교를 하게 된다. 따라서 127.0.0.1과 localhost는 다르다.
- 또한 host 뒤쪽의 resource나 identifier, query string, fragment등은 비교하지 않는다.
- SOP를 쓰는 이유
- 이메일 같은 곳에 흥미로운 주소를 담아 보내게 하고 주소를 누르면 특정한 사이트에게 명령을 내릴 수 있다.
- 하지만 SOP를 사용하면 원래 자신의 사이트와 출처가 다르기 때문에 Cross Origin이 발생해 이를 막는다.
- 그러면 다른 출처의 리소스가 필요하면 ?
CORS (Cross-Origin Resource Sharing)
CORS란 말 그대로 다른 출처의 자원을 공유하는 것이다.
CORS 접근 제어
- Simple Request
- Preflight와 달리 요청없이 바로 요청을날린다.
- 대신 아래 조건 만족해야 한다.
- GET, POST, HEAD 메서드 중 하나
- Content-Type
- A. application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- 헤더는 Accept, Accept-Language, Content-Language, Content-Type 만 허용한다.
- Preflight Request
- OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 확인하는 작업이다.
- 즉 서버에게 요청 보내도 되는지 확인한다.
- 요청이 가능하면 그 때 실제 요청을 보내게 된다.
- 즉 PR(Preflight Request)를 보내고 응답을 받 뒤 다시 실제 요청을 보내서 실제 응답을 받는 원리이다.
- 이에 맞는 포맷이 있다.
- 아래는 PREFLIGHT REQUEST에 대한 예시이다.
- Origin : 요청 출처
- Access-Control-Request-Method : 실제 요청의 메서드
- Access-Control-Request-Headers : 실제 요청의 추가 헤더 (실제로 보내는 추가 헤더들)
OPTIONS /doc HTTP/1.1
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PING...
- 아래는 PREFLIGHT RESPONSE에 대한 예시이다.
- Acceess-Control-Allow-Origin: 서버 측 허가 출처
- Access-Control-Allow-Method : 서버 측 허가 메서드
- Access-Control-Allow-Headers : 서버 측 허가 헤더
- Access-Control-Max-Age : Preflight 응답 캐시 기간
Acceess-Control-Allow-Origin: http://foo.example
- Access-Control-Allow-Method : POST, GET, OPTIONS
- Access-Control-Allow-Headers : X-PINGO..
- Access-Control-Max-Age : 88888
- 딱봐도 리소스적으로 좋지가 않다.
- 두 번 이나 왕복해야함
- 이를 캐시를 두며 살짝 해결함
- 응답 코드는 200대, 응답 바디는 비어있는게 좋다.
- 왜 굳이 Preflight?
- CORS를 모르는 서버를 위해
- CORS설정이 없는 상태로 서버를 요청을 하면 이미 서버가 처리를 다 처리를 했기 때문에 리소스적으로 개손해 + DB도 이미 처리가 끝남
- 그래서 Preflight로 처리를 하면 이런 일이 생길걱정 없음
- Credentialed Request
- 인증 관련 헤더를 포함할 때 사용하는 요청이다.
- Cookie, JWT Token 등을 자동으로 담아서 보내고 싶을때 credentials : include를 하면 된다.
- 서버도 Access-Control-Allow-Credentials :true로 설정해야 한다. (이건 Origin을 *로 허용하지 않는다.)
해결법
- 프론트 프록시 서버 설정 바꾸기 (개발 환경)
- 브라우저에선 Same Origin형식으로 프론트에 요청
- 따라서 브라우저에선 터지진 않는다.
- 직접 헤더에 설정하기
- 스프링 부트 이용하기
- 최고의 방법이다.
- 그냥 어노테이션 붙여서 쓰거나 Config에서 해결이 가능하다.