Cloudflare R2 CORS 구성하기 (Configure CORS)
CORS(Cross-Origin Resource Sharing)는 도메인 X가 도메인 Y의 리소스에 접근하는 것을 막는 표준화된 방법이에요. 도메인 Y의 HTTP 응답에 특수 헤더를 사용해, 브라우저가 도메인 Y가 도메인 X에 이 리소스 접근을 허용하는지 확인하게 만들어요.
출처: 문서
본문
CORS는 악성 웹사이트로부터 데이터를 보호하는 데 도움이 될 뿐 아니라, 버킷의 객체와 상호작용하고 버킷에 정책을 구성하는 데도 사용돼요.
CORS는 웹 브라우저에서 버킷과 상호작용할 때 사용되며, 두 가지 옵션이 있어요:
버킷을 공개로 설정: 이 옵션은 버킷을 인터넷에서 읽기 전용으로 접근 가능하게 만들어요. 누구나 브라우저나 다른 곳에서 버킷의 객체를 요청하고 로드할 수 있어요. 버킷에 공개 블로그에서 쓰이는 이미지가 있다면 이상적이에요.
Presigned URL: 고유한 URL에 접근할 수 있는 사람이 버킷에 대해 특정 작업을 수행할 수 있게 해줘요.
사전 요구사항
CORS를 구성하기 전에 필요한 것:
- 객체가 하나 이상 있는 R2 버킷. 버킷을 만들어야 한다면 Create a public bucket을 참고해요.
- 객체에 접근하는 데 사용할 도메인.
localhost도 가능해요. - (선택 사항) 접근 키. presigned URL을 만들 때만 접근 키가 필요해요.
공개 버킷에서 CORS 사용하기
공개 버킷에서 CORS를 사용하려면 버킷이 공개 접근을 허용하도록 설정되어 있는지 확인해요.
다음으로 파일 공유를 허용하도록 버킷에 CORS 정책을 추가해요.
Presigned URL에서 CORS 사용하기
Presigned URLs는 자격 증명을 노출하지 않고 버킷에 대한 특정 작업을 수행할 수 있는 임시 접근을 허용해요. presigned URL이 인증을 처리하지만, 브라우저에서 요청할 때는 여전히 CORS를 구성해야 해요.
브라우저가 다른 오리진의 presigned URL에 요청하면 브라우저는 CORS를 적용해요. CORS 정책이 없으면 presigned URL 자체가 유효하더라도 브라우저 기반 업로드·다운로드는 실패해요.
만료된 presigned URL은 403 ExpiredRequest 응답을 반환해요. R2는 만료된 presigned URL 응답에 CORS 응답 헤더를 포함하지 않으므로 브라우저 JavaScript가 오류 본문을 읽을 수 없어요. presigned URL이 만료되기 전에 갱신하거나, 브라우저가 만료 오류를 직접 처리해야 한다면 요청을 애플리케이션 서버를 통해 라우팅해요.
presigned URL로 브라우저 기반 접근을 활성화하려면:
- 애플리케이션 오리진의 요청을 허용하도록 버킷에 CORS 정책을 추가해요.
- presigned URL이 수행하는 작업에 맞게
AllowedMethods를 설정해요.GET,PUT,HEAD,DELETE를 사용해요. - presigned URL 사용 시 클라이언트가 보낼 모든 헤더를 포함하도록
AllowedHeaders를 설정해요. 콘텐츠 타입, 체크섬, 캐싱, 커스텀 메타데이터용 헤더처럼요. - (선택 사항)
ExposeHeaders를 설정해 JavaScript가ETag같은 응답 헤더를 읽을 수 있게 해요.ETag는 객체의 해시를 담고 있어 업로드 검증에 유용해요. - (선택 사항)
MaxAgeSeconds를 설정해 preflight 응답을 캐시하고 브라우저가 만드는 preflight 요청 수를 줄여요.
다음 예시는 Content-Type 헤더로 https://example.com에서 브라우저 기반 업로드를 허용해요:
[
{
"AllowedOrigins": ["https://example.com"],
"AllowedMethods": ["PUT"],
"AllowedHeaders": ["Content-Type"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]
커스텀 도메인에서 CORS 사용하기
R2 버킷에 연결된 커스텀 도메인은 CORS 정책이 있으면 크로스 오리진 요청에 대해 자동으로 CORS 응답 헤더를 반환해요.
크로스 오리진 요청에는 유효한 Origin 요청 헤더가 포함되어야 해요. 예를 들어 Origin: https://example.com처럼요. 직접 테스트하거나 curl 같은 커맨드라인 도구를 쓸 때는 요청에 Origin 요청 헤더가 없으면 CORS Access-Control-* 응답 헤더가 보이지 않아요.
캐싱과 CORS 헤더
커스텀 도메인으로 이미 트래픽을 제공 중인 버킷에 CORS 정책을 설정하면, 캐시에서 갱신되기 전까지 기존 캐시된 자산은 CORS 응답 헤더를 반영하지 않아요. CORS 정책 관련 변경 후에는 Cache Purge로 해당 호스트네임의 캐시를 제거해요.
Dashboard에서 CORS 정책 추가하기
- Cloudflare dashboard의 R2 object storage 페이지로 이동해요. Overview로 이동
- 목록에서 버킷을 찾아 선택해요.
- Settings를 선택해요.
- CORS Policy 아래에서 Add CORS policy를 선택해요.
- JSON 탭에서 정책을 직접 입력하거나 복사해 텍스트 상자에 붙여넣어요.
- 완료되면 Save를 선택해요.
정책은 버킷의 Settings 페이지에 표시돼요.
Wrangler CLI로 CORS 정책 추가하기
Wrangler CLI로 CORS 규칙을 구성할 수 있어요.
- CORS 구성이 담긴 JSON 파일을 만들어요:
cors.json
{
"rules": [
{
"allowed": {
"origins": ["https://example.com"],
"methods": ["GET"]
}
}
]
}
- CORS 정책을 버킷에 적용해요:
npx wrangler r2 bucket cors set <BUCKET_NAME> --file cors.json
- CORS 정책이 적용됐는지 확인해요:
npx wrangler r2 bucket cors list <BUCKET_NAME>
응답 헤더
R2 CORS 정책의 다음 필드는 HTTP 응답 헤더에 매핑돼요. 이 응답 헤더는 들어오는 HTTP 요청이 유효한 CORS 요청일 때만 반환돼요.
| 필드 이름 | 설명 | 예시 |
|---|---|---|
AllowedOrigins |
브라우저에서 버킷의 객체를 요청할 때 R2가 설정하는 Access-Control-Allow-Origin 헤더의 값을 지정해요. |
www.test.com의 웹사이트가 static.example.com의 커스텀 도메인에 있는 리소스(예: 폰트, 스크립트)에 접근해야 한다면, https://www.test.com을 AllowedOrigin으로 설정해요. |
AllowedMethods |
브라우저에서 버킷의 객체를 요청할 때 R2가 설정하는 Access-Control-Allow-Methods 헤더의 값을 지정해요. |
GET, POST, PUT |
AllowedHeaders |
브라우저에서 이 버킷의 객체를 요청할 때 R2가 설정하는 Access-Control-Allow-Headers 헤더의 값을 지정해요. 커스텀 헤더(예: x-user-id)를 포함한 크로스 오리진 요청은 이러한 헤더를 AllowedHeaders로 지정해야 해요. |
x-requested-by, User-Agent |
ExposeHeaders |
크로스 오리진 요청을 하는 JavaScript에 다시 노출되고 접근될 수 있는 헤더를 지정해요. safelisted 응답 헤더 너머의 헤더(예: Content-Encoding 또는 cf-cache-status)에 접근해야 한다면 여기에 지정해야 해요. |
Content-Encoding, cf-cache-status, Date |
MaxAgeSeconds |
브라우저가 CORS preflight 응답을 캐시할 수 있는 시간(초)을 지정해요. 브라우저는 최대값(86400)이 지정돼도 이를 2시간 이하로 제한할 수 있어요. | 3600 |
예시
이 예시는 Roboto-Light.ttf 객체(폰트 파일)를 담고 있는 버킷에 추가된 CORS 정책을 보여줘요.
AllowedOrigins는 사용 중인 웹 서버를 지정하고, localhost:3000은 웹 서버가 실행 중인 호스트네임이에요. AllowedMethods는 GET 요청만 허용되며 버킷의 객체를 읽을 수 있음을 지정해요.
[
{
"AllowedOrigins": ["http://localhost:3000"],
"AllowedMethods": ["GET"]
}
]
일반적으로 올바른 CORS 규칙을 설정했는지 확인하는 좋은 전략은 브라우저가 차단하는 네트워크 요청을 살펴보는 거예요.
- 규칙의
AllowedOrigins에 요청이 발생하는 오리진이 포함되어 있는지 확인해요. (http://localhost:3000또는https://yourdomain.com처럼) - 규칙의
AllowedMethods에 차단된 요청의 메서드가 포함되어 있는지 확인해요. - 규칙의
AllowedHeaders에 차단된 요청의 헤더가 포함되어 있는지 확인해요.
또한 CORS 규칙 전파는 드물게 최대 30초까지 걸릴 수 있다는 점을 알아두세요.
흔한 문제
- 크로스 오리진 요청에만 CORS 응답 헤더가 포함돼요. R2는
OriginHTTP 요청 헤더로 이러한 요청을 식별해요. 헤더 값은 정책의AllowedOrigins필드에 있는 오리진과 일치해야 해요.Origin헤더가 없는 요청은 CORS 응답 헤더를 반환하지 않아요. - CORS 정책의
AllowedOrigins값은*이거나 HTTP Origin 헤더 값을 기반으로 한 유효한 패턴이어야 해요. 유효한Origin헤더에는 경로 구성 요소가 포함되지 않고scheme://host[:port]만 포함해야 해요(port는 선택 사항).- 모든 오리진에서 요청을 허용하려면
*를 사용해요. - 오리진 패턴에는 와일드카드
*를 최대 하나만 포함할 수 있어요. 와일드카드는 점을 건너뛸 수 있어요. 예를 들어https://*.example.com은https://api.example.com과https://a.b.example.com모두와 일치하지만https://example.com과는 일치하지 않아요. - 와일드카드가 없는 오리진 값은 요청의
Origin헤더와 정확히 일치해야 해요. - 포트에는 와일드카드를 사용할 수 없어요. 여러 localhost 포트를 허용하려면
http://localhost:3000과http://localhost:5173처럼 각 오리진을 별도로 나열해요. - 유효한
AllowedOrigins값:https://static.example.com— 스킴과 호스트를 포함해요. 포트는 선택 사항이며 스킴에 의해 암시돼요. - 잘못된
AllowedOrigins값:https://static.example.com/또는https://static.example.com/fonts/Calibri.woff2— 경로 구성 요소를 잘못 포함해요.
- 모든 오리진에서 요청을 허용하려면
- 비디오 플레이어를 사용할 때처럼 오리진 페이지에서 JavaScript로 특정 헤더 값에 접근해야 한다면,
Access-Control-Expose-Headers를 올바르게 설정하고Content-Length처럼 JavaScript가 접근해야 하는 헤더를 포함해요.
더 알아보기 (Learn more)
- 공개 버킷(Public buckets) — 버킷을 인터넷에 공개하기
- Presigned URLs — 비공개 객체 접근을 위한 임시 URL