브라우저 요청에 credentials 모드가 포함되고 응답에 자격 증명을 허용할 때 Access-Control-Allow-Origin: *를 함께 쓰면 브라우저는 응답을 호출한 스크립트에 공개하지 않습니다. 허용할 origin을 정확히 돌려주고 Access-Control-Allow-Credentials: true를 설정해야 합니다.

요청의 Origin을 그대로 반사하면 안 됩니다. 서버가 사전에 정한 allowlist와 대조해야 합니다. CORS는 브라우저의 응답 읽기 규칙이지 로그인·권한 확인이 아닙니다.

CORS는 브라우저의 응답 공유 규칙입니다

다른 출처의 웹 페이지가 API 응답을 읽으려면 서버가 CORS 응답 헤더로 허용 범위를 알려야 합니다. 출처(origin)는 scheme, host, port의 조합입니다. https://app.example.test와 https://admin.example.test는 같은 서비스처럼 보여도 서로 다른 origin입니다. CORS 통과 여부가 서버의 사용자 인증이나 객체별 권한 검사를 대신하지 않습니다. 비브라우저 클라이언트는 브라우저 CORS 차단을 받지 않으므로 API는 요청마다 별도로 권한을 확인해야 합니다.

세 응답 조합을 표로 판정합니다

가상 API가 쿠키 자격 증명을 포함해 요청받는 경우의 읽기 판정 연습입니다.
Access-Control-Allow-OriginAccess-Control-Allow-Credentials브라우저 응답 읽기해석
*true차단자격 증명 요청에 wildcard origin 사용 불가
https://app.example.testtrue허용 가능실제 요청 origin과 정확히 일치해야 함
요청 Origin을 무검증 반사true안전하지 않음임의 출처에 응답을 노출할 수 있음

두 번째 행은 다른 요청 조건과 서버 설정도 맞아야 작동합니다. Access-Control-Allow-Credentials 값은 true여야 하고, Access-Control-Allow-Origin에 쉼표로 여러 origin을 나열할 수는 없습니다. 허용 origin을 하나 골라 반환하는 설계라면 서버는 먼저 요청 origin이 정확한 allowlist 항목인지 비교해야 합니다. 응답이 캐시에 저장되는 경우에는 Vary: Origin도 캐시 키가 서로 다른 출처를 구분하도록 검토합니다.

사전 요청과 실제 응답을 따로 확인합니다

JSON POST나 커스텀 헤더 요청은 브라우저가 실제 요청 전에 OPTIONS preflight를 보낼 수 있습니다. 이때 허용할 method와 header를 응답에 포함해야 합니다. 그러나 preflight가 통과했다고 실제 응답까지 읽을 수 있다는 뜻은 아닙니다. 실제 응답에도 필요한 CORS 헤더가 있어야 하며, 프레임워크가 오류 응답이나 리다이렉트에서 헤더를 누락하는지 확인해야 합니다.

가상 설정 검토 순서

  1. 브라우저 개발자 도구에서 요청 Origin, credentials 모드, OPTIONS 여부를 구분합니다.
  2. OPTIONS 응답과 실제 응답을 나눠 필요한 헤더를 기록합니다.
  3. 요청 Origin이 서버의 고정 allowlist에 있는지 비교합니다.
  4. 허용된 경우에만 정확한 origin 하나를 ACAO로 반환합니다.
  5. 자격 증명을 허용할 때 wildcard가 섞이지 않았는지 확인합니다.
  6. 프록시·CDN 캐시가 origin별 응답을 혼합하지 않는지 Vary: Origin 및 캐시 정책을 점검합니다.
  7. CORS 응답과 별개로 API의 인증 및 자원별 권한 검사가 실행되는지 확인합니다.

정상 CORS 응답은 권한 승인표가 아닙니다

브라우저 콘솔에 CORS 오류가 보인다고 항상 서버가 요청을 거절한 것은 아닙니다. 서버가 요청을 처리했더라도 브라우저가 응답을 스크립트에 노출하지 않을 수 있습니다. 반대로 공격자가 만든 페이지에서 브라우저 차단이 있더라도 API 권한 검사가 약하면 직접 요청이 가능합니다. 로그에서는 요청 처리 결과와 브라우저의 응답 공유 실패를 분리해 진단하세요.

복습: 별표 대신 무엇을 반환할까요?

문제: 로그인 쿠키를 포함한 https://app.example.test의 요청에 서버가 응답합니다. ACAO: *, ACAC: true로 충분한가요?

정답: 아닙니다. 사전 allowlist를 검사한 뒤 ACAO: https://app.example.test처럼 요청 origin과 정확히 일치하는 한 출처를 반환하고, 자격 증명 허용 헤더를 함께 설정해야 합니다. API 권한 검사는 별도입니다.

정답을 가리고 확인해 보세요

이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.

쿠키 credentials 요청에 ACAO *와 ACAC true가 내려왔습니다. 브라우저가 응답을 읽게 하려면 무엇을 바꾸며, 이것이 API 인증을 보장하나요?

정답과 해설 확인허용 origin allowlist를 검증하고 그 요청과 정확히 일치하는 ACAO 값을 반환합니다. CORS는 인증이나 권한 검사가 아닙니다.

자격 증명이 포함된 응답에는 wildcard ACAO를 쓸 수 없습니다. 서버는 임의 Origin을 그대로 반사하지 말고 허용 목록과 비교해야 합니다.

이 주제의 회상 연습 이어가기