CORS(Cross Origin Resource Sharing) 번역하면 "교차 출처 자원 공유"이다. 이렇게 번역하면 이해하기 힘드니
"교차 출처" 대신하여 "다른 출처" 라는 단어로 풀어가 보려고 한다.
CORS에 대한 설명을 하기 전에 Origin(출처)와 SOP에 대하여 정확하게 무엇을 의미하는지 알아보고 가자
Origin
위에 같은 URL 처럼 Origin은 Protocol, Host, Port까지 모두 합친 것을 의미한다. 즉, 서버를 찾아가기 위해 필요한 가장 기본적인 것들을 합쳐놓은 것이다.
또한 Origin 내의 포트 번호는 생략이 가능한데, 이는 각 웹에서 사용하는 HTTP, HTTPS 프로토콜의 기본 포트 번호가 정해져 있기 때문이다. ( HTTP -> 80 / HTTPS -> 443)
URL의 Protocol, Host, Port를 통해 같은 출처인지 다른 출처인지 판단할 수 있다
여기서 문제. http://localhost와 동일 출처인 url은 무엇일까?
1. https://localhost
2. http://localhost:80
3. http://127.0.0.1
4. https:// localhost/api/test
정답은 마지막에 적도록 하겠다. 답을 보기전에 한번 생각해보자
SOP (Same Origin Policy)
다른 출처의 리소스를 사용하는 것에 제한 하는 보안 방식이다.
쉽게 예를 들어 보도록 하겠다.
1. User가 Naver 서비스를 이용하려고 한다. 이때 인증 토큰을 받아오게 되고 인증 토큰은 세션에 저장이 된다.
2. Hacker가 User한테 요즘 유행하는 영상을 무료로 볼수있다는 링크를 보내고 User는 호기심에 링크를 클릭하게 된다.
3. 링크를 누르는 순간 hacker가 작성해놓은 script가 실행이 되면서 User의 토큰을 가져가게 된다.
4. 토큰을 통하여 Hacker는 우리의 개인정보를 알게 되고 나쁜 짓을 하게 된다. 이를 방지하는 것이 sop이다
origin을 통해 요청이 어디서 온 건지 확인하고 그 요청이 자신의 Origin과 비교하여 다른 출처인 것을 확인하여 Cross Origin이 발휘하여 접근을 막게 된다.
그렇다면 다른 출처의 리소스가 필요하다면 어떻게 해야 할까?
이때 필요한 것이 CORS(Cross origin Resource Sharing)이다.
CORS란?
추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.
CORS 접근제어 시나리오
- 단순 요청(simple Request)
- 프리플라이트 요청 (Preflight Request)
- 인증정보 포함 요청 (Credentialed Request)
Preflight Request
1. OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한 지 확인 작업
2. 요청이 가능하다면 실제 요청(Actual Request)을 보낸다.
서버에 요청을 하기 전에 서버한테 먼저 요청을 해도 되는지 확인하여 요청이 된다고 하면 접근한다.
이때 요청을 확인할 때 OPTIONS를 통하여 확인을 한다.
PREFLIGHT RESPONSE가 가져야 하는 특징
- 응답 코드는 200대 여야 한다
- 응답 바디는 비어있는 것이 좋다
SImple Request
- Preflight와 다르게 바로 요청을 날리는데 다음 조건을 모두 만족해야 한다.
- GET, POST, HEAD 메서드 중에 하나여야 하고
- Content-Type 도 아래 3개 중 하나여야 한다.
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- 헤더는 Accept, Accept-Language, Content-Language, Content-Type 만 허용된다.
그렇다면 Preflight가 왜 필요할까?
Server가 CORS를 모를 수도 있기 때문이다.
만약 Client가 삭제 요청을 하였고 그것을 Browser가 Server한테 보낸다 그럼 Server는 삭제를 하고 Browser한테 전달했는데 Browser에서 CROS가 발생한다면? 이미 Server에서는 데이터를 삭제했기 때문에 되돌리수가 없게 된다. 이때 Preflight가 필요한 것이다. Preflight가 Server에 CROS가 있는지 확인하여 없으면 Server가 동작 못하게 하고 Client한테 에러 메시지를 전달하는 것이다
Credentialed Request
인증 관련 헤더를 포함할 때 사용하는 요청이다
클라이언트 측
credentials : include
서버 측
Access-Control-Allow-Credentials : true
(Access-Control-Allow-Origin: *은 안된다)
client 측에서 사용할 url를 토큰으로 만들어서 서버 측에 보내는데 서버 측에서는
Access-Control-Allow-Credentials를 true로 해주어야 한다. * → 전부 허용으로 해주면 해킹 위험이 있기 때문에 정말 필요한 것만 해주어야 한다.
CORS 해결 방법
- 프론트 프록시 서버 설정 (개발 환경)
- 직접 헤더에 설정해주기
- 스프링 부트를 이용하기
- Spring boot 같은 경우는 @CrossOrgin 어노테이션을 붙여주면 되지만 이렇게 되면 하나하나 다 붙여줘야 하기 때문에 비효율적이다
- Configuartion을 하나 생성하여 이 효율적으로 하면 된다. 클라이언트 측 서버 측(Access-Control-Allow-Origin: *은 안된다) Access-Control-Allow-Credentials를 true로 해주어야 한다. * → 전부 허용으로 해주면 해킹 위험이 있기 때문에 정말 필요한 것만 해주어야 한다.
- 프론트 프록시 서버 설정 (개발 환경)
- 직접 헤더에 설정해주기
- 스프링 부트를 이용하기
- Spring boot 같은 경우는 @CrossOrgin 어노테이션을 붙여주면 되지만 이렇게 되면 하나하나 다 붙여줘야 하기 때문에 비효율적이다
- Configuartion을 하나 생성하여 이 효율적으로 하면 된다.
@Configuration
public class CorsConfiguartion implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api")
.allwedOrgins("http://localhost:8081");
}
}
Script
CORS는 개발이 잘못하여 나오는 에러가 아닌 크롬에서 나오는 에러이다.
지금 사용되는 사이트가 안전한 사이트인지 알 수 없기 때문에 나오는 에러이다.
위에 문제의 정답
답은 2, 4번
1번 같은 경우는 http와 https 가 서로 다른 포트 번호이기 때문에 동일 출처가 아니다
3번 같은 경우 브라우저가 url을 비교할 때 String으로 비교하는데 localhost와 127.0.0.1은 서로 다른 url로 인식하고 있다고 한다
2번은 http의 포트 번호가 80이기 때문에 인식이 되는데 뒤에 80을 작성을 안 해도 인식해주기 때문에 같은 출처로 판단이 된다.
4번은 api/cors는 추가적으로 붙는 로케이션이기 때문에 api앞에까지 비교하기 때문에 같은 출처로 판단한다.
참고
https://evan-moon.github.io/2020/05/21/about-cors/
https://www.youtube.com/watch?v=-2TgkKYmJt4
'Web' 카테고리의 다른 글
TCP UDP 란? (0) | 2024.06.04 |
---|---|
Nginx 와 Apache (0) | 2021.11.13 |
인코딩 디코딩 (0) | 2021.11.09 |
DB Connection Pool (0) | 2021.11.05 |
아스키코드 vs 유니코드 (0) | 2021.11.03 |