문제 상황
사용성 테스트 플랫폼 UTMate 개발 중 1MB 정도 크기의 JSON 로그 파일을 NCP Object Storage에 저장하고, 이를 프론트엔드에서 가져오려고 했다.
async function getLog(url){
cosnt result = await fetch(url);
...
}CORS ERROR그런데 짜잔, CORS 에러가 발생했다. CORS 에러는 잊을만 하면 등장한다
(나야 CORS)
이쯤 되면 절대 당황하지 않고 침착하다. CORS 에러는 브라우저의 오리진과 리소스 오리진이 달라서 발생하는 이슈이므로, 리소스 서버의 응답에 CORS 관련 헤더를 추가해주면 된다.
그런데 뭔가 이상하다. 외부 API를 쓰는 것도 아니고 스토리지 서비스를 쓸때 CORS에러가 발생하기도 하던가? 스토리지 서비스를 쓰다가 CORS 에러를 마주했다는 사례를 본적이 없다. 다들 이미지나 비디오를 스토리지 서비스에 저장하고 그냥 잘 불러오지 않나?
리소스를 어떻게 사용하냐에 따라 달라요
웹 보안의 기본 원칙인 동일 출처 정책(Same-Origin Policy, SOP)은 기본적으로 <img >, <video>, <script> 같은 태그로 다른 출처의 리소소를 내 웹사이트 임베딩하는 것을 허용한다. 따라서, <img > 태그로 외부 이미지 링크를 가져와 보여주려고 하면 문제없이 출력된다.
하지만 fetch 를 통해서 스크립트로 리소스 읽기를 시도하는 경우 더 엄격한 보안정책이 적용된다. 이 경우 Preflight(OPTIONS) 요청을 통해 다른 출처가 해당 리소스 읽기를 허용하고 있는지를 확인하고, 다른 출처가 헤더를 통해 리소스 읽기를 허용하고 있지 않는 경우 이를 차단시킨다.
즉 CORS 에러는 브라우저가 리소스를 그리거나 실행할때는 발생하지 않으나, 리소스를 읽으려고 할 때(자바스크립트 변수에 담을 때) 발생하는 것이다.
해결방법
이를 해결하기 위한 방법은 두가지가 있다.
1. 프록시 패턴 도입하기
브라우저가 스토리지를 직접 호출하는 대신, 우리가 제어할 수 있는 백엔드 서버를 거쳐서 데이터를 가져오는 방식이다. 우리가 제어하는 백엔드 서버는 same-origin이거나 CORS 관련 헤더를 우리가 직접 추가할 수 있으므로 CORS 에러 해결이 가능하다. 다만, API 서버 부하가 걸리므로 이 방법은 특별한 보안 요구사항이 있지 않은 경우에는 불필요한 방법이다.
2. 스토리지 서비스에 CORS 설정 추가하기
가장 정석적인 방법이다. 스토리지 서비스 설정에 CORS 설정을 변경하면 CORS 관련 헤더가 추가된다. 우리 프로젝트에서는 해당 방법을 선택했다.
NCP CORS 설정 방법
그러면 이제 콘솔에 들어가서 허용 오리진에 프로젝트의 도메인을 추가하면 된다... 그런데 NCP Object Storage 서비스는 AWS S3와 달리 CORS 정책 설정 GUI를 지원하지 않는다. (2026년 1월 기준)
NCP Object Storage 공식문서에 따르면 정해진 경로로 정해진 형식으로 HTTP 요청을 날리는 방식으로 CORS 설정할 수 있다.
요청 예시
PUT /{bucket-name}?acl= HTTP/1.1
Host: kr.object.ncloudstorage.com
X-amz-date: {Timestamp}
Authorization: {authorization-string}
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>{owner-user-id}</ID>
<DisplayName>{owner-user-id}</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>{first-grantee-user-id}</ID>
<DisplayName>{first-grantee-user-id}</DisplayName>
</Grantee>
<Permission>READ_ACP</Permission>
</Grant>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<ID>{second-grantee-user-id}</ID>
<DisplayName>{second-grantee-user-id}</DisplayName>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
</AccessControlList>
</AccessControlPolicy>
AWS SDK 사용하기
위 형식에 맞춰 요청을 보내려면 보안을 위해 시그치쳐 등 각종 항목을 추가해 보내한다. 따라서, curl을 사용하거나 자바스크립트로 직접 구현하려고 한다면 무척 번거롭다.
이 때 AWS SDK를 사용하면 보다 간편하게 해결할 수 있다.
NCP의 Object Storage는 AWS S3와 호환되는 API 구조를 가지고 있다. 따라서, 별도의 NCP 전용 라이브러리 없이 aws-sdk와 같은 도구를 그대로 사용할 수 있다.
aws-sdk 사용방법은 다음 예시들을 참고할 수 있다.
참고자료 1 : S3::PutBucketCorsCommand
참고자료 2 : AWS SDK 또는 CLI와 PutBucketCors 함께 사용
