CORS는 한창 최종 프로젝트를 해 나갈 때, 마주치게 된 녀석이다.
화면을 캡쳐해 이미지로 다운로드 되는 기능을 넣기 위해 HTML을 CANVAS로 그려주는 라이브러리를 갖다 썼었는데, 다른 건 다 잘 캡쳐가 되면서
AWS S3 버킷을 사용한 이미지들만 CORS 정책을 위배했다면서 캡쳐가 되지 않고 공란으로 나오는 현상이 발생했다.
그게 CORS와 나의 첫 만남이었다.
결국, 그때 당시에는 구글을 탈탈 털어, S3 버킷에 CORS 정책에 프로젝트 URL을 추가해주고, S3 서버에서 이미지를 불러올 때 JS에서 자동으로 타임스탬프를 초단위로 찍어주게 하여 해결을 하였다.
CORS를 알려면 먼저 SOP을 봐야한다.
브라우저는 실행 중인 웹 애플리케이션에서 가져오는 자원들의 출처를 항상 감시하고 있는데, 이 때 SOP, 즉, 자원들의 출처가 같은 웹 서버(도메인)일 경우에는 문제가 발생하지 않는다.
문제는 우리가 개발을 할 때 항상 하나의 서버에 모든 자원들을 담아두진 않는다는 것이다.
CORS와 나의 첫만남이었던 그 프로젝트에서도 처음으로 시도했던 해결방법은 이미지들을 임시적으로 로컬로 옮기는 것이었다. (정말 단순무식했다)
로컬 서버에 있는 이미지들을 아무 정책도 위반하지 않고 잘만 출력이 됐었다. 하지만 AWS S3 버킷을 사용하여 이미지를 동적으로 불러오면, CORS 정책에 위배되어 이미지가 있어야할 칸은 휑한 공란으로 표시됐다.
다시 정확히 정리하자면
는 것이다.
여기서 주목해야 할 것은 출처를 비교하는 로직은 서버가 아니라 브라우저에 구현되어 있다는 것인다.
서버는 CORS 정책을 위반했다고 할지라도 정상적으로 응답을 보내고, 브라우저 측에서 받은 응답을 가지고 출처를 판단한 후, CORS 정책을 위반했다고 판단하면 그 응답을 쓰지 않고 버려버린다.
아까도 말했듯이 보안상의 이유이다.
브라우저는 보안에 취약하다.
개발자 도구를 사용하면 가져온 스크립트 내용을 다 볼 수 있듯이,
악의를 가진 어떤 사람이 마음만 먹는다면 개인 정보와 같은 민감한 정보를
얼마든지 가져가고, 또 본인이 원하는 스크립트를 낑겨 넣을 수도 있다.
그렇기 때문에 브라우저는 인증되지 않은 출처의 리소스를 함부로 가져오지 않으려고 하는 것이다.
내가 AWS S3 버킷에 URL을 추가해줬듯이, 서버 측에서 인증된 출처라고 안심할만한 정보를 넘겨주어야 한다.
Request의 헤더에 Origin이라는 것을 추가해서 보내줘야 한다.
Origin에는 요청하는 쪽의 Scheme, Domain, Port를 담아 보낸다.
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
- Sheme: 자원에 접근할 방법을 정의해 둔 프로토콜의 이름(HTTP, FTP, TELNET 등)
- Domain: IP 주소를 보다 알기 쉽게 하기 위해 정해준 네트워크 호스트 이름
- Port: 네트워크 서비스나 특정 프로세스를 식별하는 논리 단위 (월드 와이드 웹, HTTP의 기본 포트는 80)
Response의 헤더에는 지정된 Access-Control-Allow-Origin 정보를 실어서 보내야 한다.
대부분은 이렇게 하면 해결이 되는데, S3 버킷의 이미지들을 Canvas로 재구성할 때 다시 Cross-Origin 정책을 위반한다고 나온다.
이에 대해서는 여러가지 해결책이 있지만, 내가 사용했던 방법은
이미지를 재사용하지 않고 새로 내려받게 하기 위해서 S3 버킷에 이미지 다운로드 요청을 보낼 때 GET 요청의 Parameter로 Timestamp와 같은 값을 추가하여 요청이 발생할 때마다 다른 URL을 사용하도록 해서 문제를 해결하였다.