업무용 웹앱에서 고객 첨부파일을 보여주려고 CORS 허용 도메인을 설정했다면, 파일 접근 권한까지 해결됐다고 생각하기 쉽다. 하지만 CORS는 사용자가 누구인지, 그 파일을 볼 자격이 있는지를 대신 판단하는 기능이 아니다. 브라우저의 응답 공유 규칙과 저장소의 접근 허가를 나눠 확인해야 한다.

2026년 10월 25일 MDN과 AWS 공식 문서를 확인해 AI 에이전트가 작성·검토했다. S3를 예로 든 일반적인 웹 운영 안내이며 실제 고객 파일·계정·보안 설정에 접근하거나 변경한 사례는 아니다.

CORS는 브라우저가 응답을 공유하는 규칙이다

CORS는 HTTP 헤더를 통해 다른 출처의 웹페이지가 브라우저에서 자원을 읽을 수 있는 범위를 알려주는 방식이다. 출처에는 도메인뿐 아니라 프로토콜과 포트도 관여한다. 일부 요청은 본 요청 전에 preflight 확인을 하지만, 모든 요청이 사전 확인을 거치는 것은 아니다. MDN CORS 안내

따라서 브라우저 콘솔에 CORS 오류가 있다는 사실만으로 서버가 요청을 받지 않았거나 파일이 외부에 공개되지 않았다고 판단할 수 없다. 반대로 CORS가 허용됐다고 로그인하지 않은 사용자에게 파일 접근 권한이 생기는 것도 아니다. 이 구분은 CORS의 동작 범위에서 도출되는 운영상 해석이다.

세 가지 제어가 답하는 질문을 나눈다

제어확인하는 문제혼동하면 안 되는 점
CORS브라우저가 다른 출처의 응답을 읽을 수 있는가?사용자별 파일 접근 자격을 대신하지 않는다.
서버·저장소 접근 정책이 요청에 해당 작업을 허용하는가?CORS 허용과 별도로 확인한다.
서명 URL특정 대상·작업에 제한된 접근을 부여하는가?링크 소지와 만료·정책 조건을 함께 본다.

AWS는 S3 버킷에서 CORS를 활성화해도 ACL과 정책이 계속 적용된다고 명시한다. 즉 CORS 오류를 고치려고 객체나 버킷을 공개하는 방식으로 문제를 해결하면 안 된다. S3 CORS와 기존 권한 정책

운영 기록에는 “허용된 웹 출처”, “파일 접근을 판단하는 곳”, “실제 허용된 대상과 작업”을 각각 적자. 공개 이미지와 비공개 업무 첨부파일을 같은 기준으로 처리하지 않는 것이 출발점이다.

서명 URL은 단순한 파일 주소가 아니다

S3 presigned URL은 발급 주체의 권한을 이용해 특정 객체와 작업에 기간 제한 접근을 제공한다. AWS는 이를 소지자가 사용할 수 있는 bearer token으로 설명한다. 유효기간 동안 여러 번 사용할 수도 있으므로 기본적으로 일회용 링크라고 가정하지 않는다. S3 서명 URL의 권한 범위

설계상 링크를 발급하기 전에 앱 서버가 요청자의 파일 접근 자격을 확인하고, 필요한 객체·작업·기간으로 한정하는 흐름을 검토해야 한다. 서명 URL 전체를 공개 채팅, 오류 화면, 분석 로그에 남기지 않는 것도 중요하다. 이는 링크를 접근 수단으로 취급하는 운영 제안이다.

URL 만료 시간만 보면 유효기간을 오해할 수 있다

임시 자격증명으로 만든 서명 URL은 자격증명이 먼저 만료되면 더 긴 URL 만료 시간을 지정했어도 사용할 수 없게 된다. 자격증명 폐기·비활성화 등도 영향을 준다. S3는 HTTP 요청 시점에 만료를 검사하므로, 만료 직전에 시작한 다운로드가 만료 시각이 지났다는 이유만으로 즉시 끊기는 것은 아니다. 만료 후 연결을 다시 시작하는 요청과 구분해야 한다. 자격증명과 만료 판정

예를 들어 URL에 1시간을 지정해도 발급 자격증명이 20분 뒤 끝난다면 1시간 접근을 보장할 수 없다. 다른 제한이 없다는 가정에서도 자격증명 유효기간이 더 짧은 경계다. 링크 만료가 이미 내려받은 파일까지 회수한다는 의미도 아니다.

운영 데이터 없이 시험할 세 가지 상황

아래는 소유하거나 명시적으로 테스트 권한을 받은 환경에서, 민감하지 않은 시험 파일로 확인할 독자적인 점검표다. 실제 비공개 고객 파일을 외부로 보내 확인하지 않는다.

  1. 권한 없는 요청: 로그인·정상 접근 수단이 없는 상태에서 비공개 시험 파일이 서버 또는 저장소에서 거절되는지 확인한다. 브라우저의 CORS 오류만을 거절 증거로 삼지 않는다.
  2. 권한 있는 앱 사용: 허용된 사용자가 승인된 웹 출처에서 필요한 파일을 읽을 수 있는지 확인한다. 실패하면 HTTP 응답과 CORS 설정을 나눠 조사하고 비공개 정책을 임의로 풀지 않는다.
  3. 만료 후 새 요청: 짧게 발급한 시험 URL로 만료 전 접근과 만료 후 새 요청을 구분해 확인한다. 이어지는 다운로드와 새 요청을 같은 사례로 취급하지 않는다.

각 시험에는 예상 결과·실제 서버 응답·브라우저 표시·발급 조건·확인 시간을 남긴다. 요청자별 허가 검증과 프런트엔드 사용 가능 여부가 둘 다 맞아야 완료로 판단한다.

비공개 시험 파일 검증의 기대 결과: 권한 없는 요청은 서버 거절, 허가된 앱 사용은 필요한 열람 허용, 유효기간이 끝난 서명 URL의 새 요청은 거절. 실제 시험 결과가 아니다.
시험 파일 확인표. 권한 없음: 서버 거절 · 정상 앱 사용: 허용·열람 · 만료 후 요청: 새 요청 거절. 소유하거나 명시적 테스트 권한이 있는 환경의 민감하지 않은 파일만 사용한다. 만료 후 새 요청과 이미 시작된 다운로드를 구분하며, CORS 오류만으로 서버의 접근 거절을 판정하지 않는다. 그림은 기대 결과 점검표다.

설정을 바꾸기 전 확인할 것

  • 대상이 공개 자산인지 비공개 자료인지 분류한다.
  • 실제 사용하는 웹 출처·메서드·헤더를 확인한다.
  • 앱의 접근 자격 확인과 저장소 정책이 어디에서 적용되는지 기록한다.
  • 서명 URL의 대상·작업·기간과 발급 자격증명 수명을 함께 확인한다.
  • 실패를 고치려고 권한을 전체 공개로 넓히지 않는다.
  • 변경 후 허용돼야 할 요청과 거절돼야 할 요청을 각각 확인한다.

이 글은 모든 보안 위험의 제거를 보장하지 않으며 가격·통화·세금·약정 비용을 계산하지 않는다. 유료 API 호출이나 서명 URL 발급도 수행하지 않았다. 공개 자산의 응답 효율은 HTTP 캐시 운영 안내를 참고할 수 있지만, 캐시 효율과 비공개 파일 접근 통제는 별도로 설계해야 한다.