웹 클라이언트 제작할 떄, 왼쪽이 localhost:3000, 오른쪽이 https://dev.~~ 등의 api 서버라고 생각하기.
아주 잘 정리해 주셨고, 전체 흐름도 크게 틀리지 않습니다. 말씀하신 번호 순서대로 답변을 드리겠습니다.
1. A.com에서 클라이언트에 a.html을 준다.
- 맞습니다. 사용자가 브라우저에서 A.com에 접속하면, 서버(A.com)가 a.html을 응답으로 보내주는 상황입니다.
2. a.html을 분석(파싱)하는 중, 이 파일 안에 B.com의 파일이 있어 GET 요청을 해야 한다.
- 맞습니다. a.html 내부에 <script src="B.com/xxx.js"> 또는 <img src="B.com/yyy.png"> 이런 식의 참조가 있을 수 있죠. 브라우저는 이를 해석하면서 필요한 리소스를 가져오려고 자동으로 B.com에 요청을 보냅니다.
3. 이때, 클라이언트가 B.com으로 요청을 날리는지, 아니면 a.html 자체에서 B.com으로 요청을 날리는지?
- 브라우저가 요청을 날린다는 표현이 좀 더 적절합니다.
- a.html이 “직접” 요청을 보내는 것처럼 보이지만, 실제로는 브라우저(클라이언트) 가 HTML 파서 과정에서 B.com/xxx.js나 B.com/yyy.png 등을 가져오기 위해 자동으로 요청을 보냅니다.
- 즉, “a.html 자체가 요청한다”라고 말하는 것보다는 브라우저가 a.html을 해석한 결과로 B.com에 HTTP 요청을 보내는 것이라 보시면 됩니다.
4. OPTIONS / 으로 B.com 요청에 Host: B.com, Origin: A.com을 날린다. 이 때
브라우저가 CORS 정책에 따라 사전에 Preflight 요청(사전 확인 요청)을 날릴 수 있습니다. 일반적으로 다음과 같은 조건에서 OPTIONS 요청(Preflight)이 발생합니다.
- PUT, PATCH, DELETE, 혹은 POST 등 표준이 아닌 메서드로 요청할 때(예: application/json 등 특정 헤더와 함께),
- 특수한 헤더를 함께 보내야 할 때(예: X-Requested-With, Authorization 등),
- 쿠키(Credentials)를 포함한 요청을 보낼 때 등.
단순히 <img src> 나 <script src>처럼 단순 GET으로만 B.com에 요청하는 경우라면, 일반적으로 OPTIONS(Preflight)을 건너뛰고 바로 GET 요청을 보내는 경우가 많습니다. (이는 Simple request라 부릅니다.)
하지만 실제 코드에서 특정한 CORS 헤더나 인증이 개입되는 상황이라면, OPTIONS 요청이 발생하는 시나리오가 충분히 생길 수 있습니다.
4.1. Origin을 왜 꼭 붙여지는지? 그냥 안 붙여도 되지 않나?
- 브라우저가 보안을 위해 자동으로 설정하는 헤더입니다.
- 기본적으로 동일 출처 정책(Same-Origin Policy) 때문에, 브라우저는 스크립트가 어떤 출처(Origin)에서 로드되었는지 인지하고 있어야 합니다.
- CORS는 “내 자원에 접근하는 외부 출처(origin)가 어디인지”를 서버가 알 수 있게끔 Origin 헤더를 붙여 전송하고, 서버가 응답 시에 Access-Control-Allow-Origin: A.com 식으로 허용 여부를 판단하게끔 한 것입니다.
- “안 붙이면” 웹 표준이 허용하지 않습니다. 브라우저가 임의로 헤더를 제거해버리면, 악의적인 페이지에서도 CORS 규칙을 우회해 민감 정보를 끌어가는 등의 보안 문제가 생기기 때문입니다.
5. B.com에 사전에 A.com에서 온 요청은 승인한다고 작성되어있기 때문에 가능하다는 응답을 A.com에게 줌. B.com에 미리 작성이 되어있지 않았다면 CORS 에러가 떴을 것임.
- 정확합니다. B.com 서버가 Access-Control-Allow-Origin: A.com (또는 *) 등을 반환해주면, 브라우저가 “승인”으로 판단하고, 이후의 실제 요청/응답을 진행할 수 있게 됩니다.
- 만약 B.com 서버가 CORS 헤더를 아예 주지 않으면, 브라우저는 보안상 에러(콘솔에 CORS 에러)를 내고 요청을 차단해 버립니다.
5.1. 이 때, 애초에 B.com으로 요청을 보낼 때, 그냥 Origin 없이 보냈다면 해결되었을 문제 아닌가? 왜 이렇게 복잡하게 하는 걸까?
- 브라우저는 표준에 따라 Origin 헤더를 붙이도록 강제되어 있습니다. 사용자가 임의로 브라우저 레벨에서 HTTP 헤더를 뺄 수 없습니다(개발자 도구로 억지로 헤더를 조작하는 건 별개의 이야기이긴 하지만, 일반 사용자/일반 상황에선 불가능하다고 봐야 하죠).
- 만약 Origin을 붙이지 않고 외부로 리소스를 요청할 수 있게 두었다면, 다른 사이트에서 임의로 스크립트를 호출해 민감한 정보(쿠키가 있는 API 등)를 전송하거나, 크로스 사이트 스크립팅(XSS)과 결합해 보안 취약점이 크게 생길 수 있습니다.
- 때문에 “안 붙이면 되지 않느냐”는 것은 현실적으로 표준과 브라우저 정책에 반하는 일이고, 이 복잡한 정책(CORS)은 웹 상의 보안을 지키기 위한 필수 장치입니다.
6. 여전히 Origin: A.com을 넣은 채로 파일을 잘 주고 받는다.
- 맞습니다. CORS 허용 정책 하에, B.com은 A.com에서 오는 요청을 승인했고, 브라우저에서는 정상적으로 Origin을 붙인 상태로 리소스를 주고받을 수 있습니다.
결론
- CORS 절차와 “a.html 안에서 B.com을 요청 시도 -> 브라우저가 Origin 헤더 자동 첨부 -> B.com에서 CORS 정책 확인 -> 정상 응답” 이런 과정은 질문자님이 설명하신 대로 거의 정확합니다.
- Origin 헤더를 빼버릴 수 있으면 편할 것 같아도, 웹 표준과 브라우저의 보안 정책 때문에 불가능한 것이고, 이를 통해 크로스 사이트 요청이 어떻게 이뤄지는지, 그리고 어느 출처에서 온 요청인지 서버가 알 수 있게끔 하는 것이 CORS의 핵심입니다.
정리하자면, “(4.1과 5.1에서) 굳이 Origin을 붙여야 하냐, 안 붙이면 안 되냐?” → 보안상의 이유와 웹 표준에 의해 반드시 붙게 되어 있으며, 사용자/개발자가 임의로 제거할 수 없다가 핵심 이유입니다.
You said:
브라우저가 Origin 헤더를 강제로 붙이고 제거할 수 없게 하는 가장 큰 이유는 보안입니다.
만약 브라우저가 Origin을 보내지 않거나, 임의로 뺄 수 있었다면 서버 입장에서는 “이 요청이 어디서부터 왔는지”를 명확히 알 수 없게 되고, 크로스 사이트 요청을 악용하는 공격(CSRF, XSS 등)이 훨씬 쉬워집니다.
아래는 “Origin”을 없앨 수 있다면 생길 수 있는 보안 문제가 어떤 것인지, 구체적인 예시를 들어 설명해 드립니다.
1. 크로스 사이트 요청 위조(CSRF) 공격 시나리오
- 사용자(U)가 은행 사이트 bank.com에 로그인하고, 해당 사이트에 유효한 로그인 세션 쿠키가 이미 저장되어 있다.
- 공격자(A)가 만든 악성 사이트 evil.com 에 사용자가 접속한다.
- evil.com의 스크립트가 bank.com에 중요한 데이터를 요청하거나, 송금 등의 위험한 요청을 보낸다.
- 브라우저가 Origin을 보내지 않는다면, bank.com 서버는 “이 요청이 evil.com에서 왔는지” 모른다.
- 서버는 ‘내가 준 세션 쿠키’(=유효한 로그인 상태)만 보고 정상적인 요청처럼 처리할 위험이 있다. 결과적으로 공격자가 사용자의 돈을 가로채는 등 심각한 피해가 발생한다.
- 현실에서는 브라우저가 자동으로 Origin: evil.com 을 붙이므로, bank.com은 “이 요청은 evil.com에서 왔네?”를 인지하고 CORS 정책 혹은 CSRF 방어 로직을 통해 요청을 거부하거나 적절한 인증 과정을 밟도록 할 수 있다.
이처럼 Origin이 없다면 서버가 요청 출처를 구분하기 어려워 ‘악의적’인지 ‘정상적인’ 것인지 판단을 못 하게 됩니다.
2. 민감 정보 노출 시나리오 (데이터 훔쳐보기)
- 사용자가 개인정보가 있는 사이트 private.com에 이미 로그인(쿠키로 인증)한 상태.
- 공격자 사이트 attack.com에 접속했을 때, 스크립트가 private.com API로부터 개인정보(예: 이메일, 연락처 등)를 가져오려고 시도한다.
- 브라우저가 Origin을 붙이지 않는다면 private.com 서버는 “이 요청이 내부 리소스(같은 출처)인가 외부 리소스인가?”를 파악하기 어렵습니다.
- 특히, 예전에 CORS가 없던 시절에는 <img src="private.com/userinfo">나 <script src="private.com/userinfo"> 등을 악용해서 서버 응답을 브라우저에서 확인하는 기법들이 존재했습니다.
- 현재 표준 브라우저에서는 해당 요청에 Origin: attack.com을 포함하고, private.com이 CORS 허용 정책에 attack.com을 넣지 않았다면, 브라우저가 데이터 열람을 막습니다.
3. 왜 ‘그냥 Origin을 안 붙이면 편하잖아?’가 안 되는가?
- 서버 보안 정책(CORS)
- 서버 입장에서는 “어떤 사이트에서 요청했는지”를 확인해야, 허락해줄지 말지 판단 가능합니다.
- Origin을 제거해버리면, CORS가 무의미해지고, 서버는 임의로 들어온 요청에 대해 출처 식별이 불가능해집니다.
- 결국 “어떤 사이트라도 내 API를 마음껏 호출” 하는 상황이 생길 수 있어, 민감 정보 도용 위험이 커집니다.
- 브라우저 표준(CORS 스펙)
- W3C에서 정의한 CORS 스펙에 따르면, 크로스 사이트 요청 시 반드시 Origin을 명시하도록 규정되어 있습니다.
- 브라우저는 이 표준을 구현했기 때문에, 개발자가 임의로 Origin 헤더를 제거할 수 없고, 자동으로 붙이는 것을 막을 수 없습니다.
- 보안 취약점 극복 역사
- 과거엔 X-Requested-With: XMLHttpRequest 같은 헤더를 이용해 서버가 “Ajax 요청인지”를 구분하려는 방안도 있었지만, 이는 충분하지 않았고, 현재는 CORS(Origin, Access-Control-Allow-Origin, 등)가 확립되었습니다.
- 만약 Origin이 빠진 채로 자유롭게 요청할 수 있었다면, 이미 알려진 다양한 웹 취약점이 다시 부활하게 됩니다.
요약
“Origin 헤더를 제거하면 안 되나?”
→ 안 됩니다. 브라우저 표준에서 반드시 붙이도록 강제하며, 이는 크로스 사이트 요청 공격(CSRF, XSS)에 대한 주요 방어 수단이기 때문입니다.Origin을 통해 서버가 “이 요청이 어디서부터 왔는가”를 식별할 수 있고, 적절히 허용/차단할 수 있습니다. 만약 이를 제거할 수 있다면, 공격자가 사용자의 쿠키나 인증 정보를 활용해 임의의 요청을 보내고 서버 응답도 탈취하는 등 매우 간단히 보안을 뚫게 됩니다.
결국 CORS 정책의 목적은 “내가 허용한 출처(Origin)인지 명확히 알고 나서 응답을 주겠다”라는 것이므로, 브라우저는 이를 수행하기 위해 “Origin 헤더”를 절대 빼지 않도록 설계되어 있습니다.
'기술 > 기타' 카테고리의 다른 글
Multi-task learning (0) | 2022.01.05 |
---|---|
youtube data api 사용했던 방법 (0) | 2021.10.24 |
공통적으로 자주쓰는 colab 명령어들 모음 (0) | 2021.08.28 |