Firebase CORS 오류 해결: Storage 이미지 업로드가 막힐 때 확인할 설정

··설명 약 5분·작성: 해비·블로그 소개

Firebase Storage 업로드의 CORS 오류를 요청 정보와 버킷 설정으로 어떻게 확인하나요?

Storage 업로드가 막혀도 Console의 CORS 문구만으로 원인을 확정하지 마세요. 요청 호스트·메서드·Origin·OPTIONS·최종 상태와 SDK 오류를 함께 기록합니다.

적용 조건·범위: 아래는 직접 파일을 읽는 GET/HEAD 예시입니다. 업로드 요청에서 실제로 PUT 또는 POST가 필요한 것을 확인한 경우 그 메서드를 추가합니다. OPTIONS 자체를 CORS method 목록에 추가하지 않습니다. origin에는 경로를 제외한 프로토콜·호스트·포트가 들어갑니다. http://localhost:3000과 http://localhost:5173은 다릅니다.

본문 근거: cloud.google.com/storage/docs/using-cors · firebase.google.com/docs/storage/web/download-files · firebase.google.com/docs/storage/web/handle-errors

학습 목표와 사전 지식

목표: Storage 업로드 실패에서 CORS·인증·버킷 설정을 분리하고 필요한 CORS만 수정합니다.
사전 지식: Origin 개념, Network 탭, Cloud Storage 버킷 관리 권한

CORS는 브라우저가 다른 출처 응답을 읽을 수 있는지 정하는 정책입니다. Storage Rules가 허용할 사용자와 객체를 정하는 것과 다릅니다. 콘솔의 CORS 문구 하나로 Rules나 버킷을 전부 공개하지 마세요.

요청 종류부터 고정하기

실패한 요청의 호스트, HTTP 메서드, Origin, OPTIONS 응답, 최종 상태 코드와 SDK error.code를 기록합니다. Firebase Web SDK 업로드인지, getBlob/getBytes 직접 다운로드인지, 직접 만든 fetch 업로드인지 먼저 구분합니다. 잘못된 bucket이나 API 응답이 CORS 문구 뒤에 가려질 수 있으므로 SDK 오류와 Console의 객체 존재 여부도 함께 봅니다.

관찰 다음 확인
storage/unauthorized 로그인 상태·경로·Storage Rules
storage/object-not-found 실제 객체 이름·bucket
OPTIONS 또는 응답에 CORS 헤더 없음 실제 요청 Origin과 버킷 CORS
storage/quota-exceeded 프로젝트 플랜·사용량·버킷 접근 조건
CORS와 권한 구분: 브라우저 Origin, 버킷 CORS, Storage Rules

cors.json: 필요한 출처와 메서드만

아래는 직접 파일을 읽는 GET/HEAD 예시입니다. 업로드 요청에서 실제로 PUT 또는 POST가 필요한 것을 확인한 경우 그 메서드를 추가합니다. OPTIONS 자체를 CORS method 목록에 추가하지 않습니다. origin에는 경로를 제외한 프로토콜·호스트·포트가 들어갑니다. http://localhost:3000과 http://localhost:5173은 다릅니다.

cors.json · 전체 설정 파일; 예시 출처를 실제 소유 출처로 교체

[
  {
    "origin": [
      "http://localhost:3000",
      "https://example.com"
    ],
    "method": [
      "GET",
      "HEAD"
    ],
    "responseHeader": [
      "Content-Type"
    ],
    "maxAgeSeconds": 3600
  }
]

터미널 · 버킷 소유 프로젝트에서 실행할 명령; 여기서는 미실행

gcloud storage buckets describe gs://YOUR_BUCKET --format="default(cors_config)"
gcloud storage buckets update gs://YOUR_BUCKET --cors-file=cors.json
gcloud storage buckets describe gs://YOUR_BUCKET --format="default(cors_config)"

수정 전·후 비교

먼저 기존 CORS를 별도 파일로 보관합니다. 위 설정은 CORS 목록을 교체하므로 기존 운영 Origin을 누락시키지 마세요. 변경 후 같은 요청을 DevTools의 캐시 비활성화 상태에서 다시 보냅니다. preflight 캐시가 남을 수 있어 새로운 시크릿 세션에서도 확인합니다. 응답을 읽을 수 있고 원래 요청이 성공해야 해결이며, CORS 문구만 사라지고 403이 남으면 권한 문제는 아직 남아 있습니다.

CORS와 권한 구분 해결: 오류 확인, 도메인 허용, 업로드 검증

브라우저 밖의 검사에는 한계가 있습니다

curl이나 새 탭 직접 접근은 CORS 정책을 동일하게 적용하지 않습니다. 성공해도 fetch의 성공을 증명하지 못합니다. 다운로드 token URL과 인증 SDK 요청은 인증 수단도 다르므로 같은 요청으로 취급하지 않습니다. 계정 권한과 파일 크기·유형 검사는 Storage Rules에 유지하세요.

설정을 바꾸기 전 3가지 관찰

cors.json 예제에는 localhost:3000의 GET·HEAD와 example.com만 있습니다. 아래 경우를 DevTools의 실제 Request URL·Origin·Method·Response Headers에서 판단해 보세요.

관찰 원인 후보 다음 행동
localhost:5173의 GET에서 preflight 또는 응답 헤더가 Origin을 허용하지 않음 예제 origin에 5173이 없음 실제 사용 출처라면 5173을 추가하고 기존 운영 출처는 보존
localhost:3000의 직접 PUT 요청에서 메서드가 허용되지 않음 예제 method에 PUT이 없음 실제 요청 방식이 PUT인지 확인한 뒤 필요한 경우에만 추가
CORS 응답 헤더가 정상이고 최종 응답이 403·storage/unauthorized Origin 문제 이후 권한 거부 현재 UID·객체 경로·Storage Rules 점검

기존 설정은 변경 전에 로컬 파일로 기록하세요. 아래 명령의 결과는 조회용 출력이며 --cors-file에 그대로 넣는 JSON 배열 형식과 같다고 가정하지 마세요.

gcloud storage buckets describe gs://YOUR_BUCKET --format="default(cors_config)" > cors-before.txt

위 표를 맞힌 뒤에만 본문의 cors.json을 실제 Origin·메서드에 맞게 수정하고 변경 전후를 비교하세요. 이 편집에서는 버킷 설정을 읽거나 변경하지 않았습니다.

직접 확인할 결과

기존 CORS 백업과 변경 후 목록 대조
동일 Origin·메서드 브라우저 재시도
403·404와 CORS 해결 여부 별도 기록

사용 전 플랜 확인

2026-09-13 공식 문서 기준 Cloud Storage for Firebase는 기본 버킷 접근을 포함해 Blaze 종량제 플랜이 필요합니다. 무료 사용량과 결제 플랜은 다른 개념입니다. 개발 프로젝트의 결제 연결·예산 알림·실제 사용량을 확인하세요.

검증 범위와 기준일

공식 문서 확인일: 2026-09-13. 웹 SDK 예제는 모듈형 API 기준입니다. 이 글의 코드·구조 정적 검토와 실제 클라우드 인증·저장·배포 검증을 구분합니다. 본인 개발 Firebase 프로젝트의 실제 인증·권한·배포 요청은 이 편집 환경에서 실행하지 않았습니다.

이어서 학습하기

공식 문서

이 글이 도움이 되었나요?

조회 중

읽음 기록

읽음 — / 전체 20개 · 필수 14개

이 글을 쓴 해비

웹사이트를 제작·운영하고, 개인 서비스와 자동화·AI 도구를 만듭니다. 직접 만들며 배운 내용과 문제 해결 과정을 BlogFlow에 기록합니다.

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기