You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
이 3가지가 같은 경우, 동일 출처(Origin) 다른 경우에 교차 출처(Cross-Origin) 가 됩니다.
출처(origin): 요청을 보내는 웹사이트와 요청을 받는 API 서버의 주소를 말합니다.
✅ 쉽게 알아보는 CORS란?
브라우저는 사용자가 접속한 웹사이트와 다른 출처(도메인, 포트, 프로토콜)를 가진 리소스에 접근하려고 할 때, 이 요청을 허용할지 말지를 결정합니다. 즉, 내가 만든 웹사이트aaa.com가 다른 도메인(예: bbb.com)의 API에 데이터를 요청할 때, 브라우저는 이를 차단할 수 있습니다.
💬 왜 차단될까?
브라우저는 ‘보안’을 위해 사용자가 방문한 웹사이트aaa.com 외부의 다른 사이트를 완전히 신뢰하지 않기 때문입니다. 특히, 사용자 정보나 자원을 무단으로 접근하는 것을 막기 위해 이런 제한이 걸려 있습니다.
💬 하지만, Postman이나 서버에서 같은 요청을 보내면 통과된다! 왜 그럴까?
Postman이나 백엔드에서는 CORS 정책을 따르지 않기 때문입니다. CORS는 오로지 브라우저(크롬, 엣지, 사파리같은 프론트엔드)가 적용하는 보안 정책이기 때문에 서버 사이에서는 아무런 문제 없이 데이터를 주고받을 수 있습니다.
💬 로그인이 유지되는 원리?
로그인이 유지되는 원리는 보통 브라우저에 저장된 인증 정보(예: 쿠키 🍪) 덕분입니다.
예를 들어,
내가 sopt.com이라는 사이트에 로그인하면, 브라우저는 인증 정보를 쿠키에 저장합니다.
이후 sopt.com에 다시 접속하거나 그 사이트의 API에 요청을 보낼 때, 브라우저는 이 인증 정보를 자동으로 포함해 서버에 전송합니다.
서버는 이 정보를 통해 내가 이전에 로그인한 사용자임을 식별하고 로그인 상태를 유지합니다.
🚫 그런데! 만약 범죄자들이 나쁜.com이라는 사이트를 만들어 내 정보를 빼내려 한다면 어떻게 될까요?
내가 나쁜.com 에 접속하게 되면, 그 사이트의 HTML, CSS, JavaScript 코드가 내 브라우저에 로드됩니다.
이 코드로 인해 범죄자들이 브라우저에서 sopt.com의 쿠키와 같은 인증 정보를 사용하여 sopt.com서버에 악의적인 요청을 보낼 수 있는 상황이 발생할 수 있습니다.
예를 들어, 나쁜.com이 sopt.com에 나의 개인정보 조회 요청을 보내고, 그 응답 데이터를 탈취하여 자신의 서버로 전송할 수 있습니다.
→ 이처럼 브라우저에 저장된 정보가 사용자의 의지와 무관하게 악용될 수 있기 때문에, **SOP(Same-Origin Policy, 동일 출처 정책)**이라는 보안 정책이 이를 방지합니다. 동일 출처 정책은 오직 동일한 출처(Origin)에서만 데이터를 접근할 수 있도록 제한하여, 외부 출처에서 무단으로 데이터를 가져가는 것을 막습니다. (기본적으로 브라우저는 SOP 를 따릅니다.)
🐰 오늘 우리가 알아볼 **CORS(Cross-Origin Resource Sharing)**는 동일 출처 정책에 대해서 예외를 허용하는 방식! 브라우저의 개발자 도구에서 “CORS 오류”가 발생할 경우, 이는 “해당 요청을 허용하려면 CORS를 설정하라”는 의미로 이해하면 됩니당~ 저희 서버가 꼭 해 주어야 할 작업이에요!
(ex) sopt.com에서 네이버 지도 API를 호출하려 할 때, 이 둘은 서로 다른 출처이기 때문에 기본적으로 리소스 요청이 차단됩니다. 이처럼 서로 다른 출처에서 리소스를 주고받는 것은 디폴트로 허용되지 않습니다. 이를 가능하게 해주는 것이 바로 CORS !
✅ 좀 더 깊게 알아볼까? CORS란?
CORS 의 동작 방식을 조금 더 깊게 살펴봅시다!
💬 CORS 요청 과정
sopt.com에서 네이버 지도 API로 요청을 보내는 상황을 가정
→ 서로 다른 출처로의 요청이니까 cross-origin 요청이다.
Origin 헤더 추가
브라우저는 다른 출처로 요청을 보낼 때 Origin 이라는 헤더(받는 쪽의 IP 주소, 사용할 프로토콜이나 옵션 등의 정보가 담김)를 자동으로 추가
요청을 받은 네이버 지도 API 서버는 응답할 때 헤더에 Access-Control-Allow-Origin을 포함하여 보냅니다. 서버에 sopt.com이 허용된 출처로 등록되어 있다면 이 값이 응답 헤더에 포함됩니다.
브라우저는 요청 출처가 서버의 Access-Control-Allow-Origin 값과 일치하는지 확인한 후, 일치하면 응답을 허용하고, 그렇지 않으면 CORS 오류가 발생!
추가적인 보안 설정
토큰 등의 사용자 식별 정보가 담긴 요청에는 더 엄격하다!
credential 옵션: 요청을 보내는 쪽에서 credential 옵션을 true로 설정해야 한다.
정확한 출처 지정: Access-Control-Allow-Origin 값에 * (와일드카드) 대신 특정 출처(URL)를 명시해야 합니다.
Access-Control-Allow-Credentials: 서버 응답의 이 항목을 true로 설정해줘야 민감한 정보를 포함한 요청이 허용됩니다.
지금 설명한 방식은 Simple Request라고 해서 GET,POST 등의 기본 요청에 사용되는 것입니다. 이 경우 브라우저는 추가적인 검증 없이 요청을 바로 전송합니다.
PUT, DELETE 등 처럼 서버의 데이터를 변경할 가능성이 있는 요청에는 사전 확인이 필요하겠죠?
→ 브라우저는 본 요청을 보내기 전에 OPTIONS 메서드로 서버에 Preflight Request을 보내서, 본 요청을 허용할지를 검증합니다.
✅ CORS에서 보내는 요청들은 2가지의 종류!
1️⃣ Simple Request
기본적인 GET, POST, HEAD 처럼 일반적인 요청에서 사용
요청을 보내기는 보내는데, 서버가 CORS 설정 안해줘서 통과를 못하면 응답 데이터만 못 받아오는 것
요청 자체는 서버에 도달하지만, 응답을 브라우저에서 차단함
즉, 요청이 성공적으로 서버에 도착 → 데이터 갱신 → 브라우저는 서버의 응답 데이터를 가져오지 않음 → 사용자는 응답을 확인할 수 없음!
2️⃣ Prefighted Request
주로 서버에 side effect를 일으킬 수 있는 HTTP 요청 메서드(DELETE, PUT)에 대해 사용
cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 요청을 보내는 것도 일단 미리 허락을 받아야 한다!
OPTIONS 메서드를 사용해 서버에 “이 요청을 보내도 될까요?”라고 먼저 물음 → 이후, 서버가 해당 요청을 허용한다고 응답 시 → 실제 요청이 보내짐
+++
BUT,,,,, Simple Request로 보내는 요청도, 서버가 CORS 설정을 신경 쓰지 않거나 보안 조치를 충분히 하지 않으면 서버에 저장된 데이터에 변경이 가해질 수 있기 때문에, 무조건적으로 SOP만 믿을게 아니라 서버 측에서도 그런 것들을 고려해 보안 설정을 철저히 하는 등 안전하게 프로그래밍 해야합니다!!
✅ CORS의 처리 방법
프로젝트 코드 단에서 잡는 방법 (Spring Boot)
✅ 우리가 배포할 인프라 단에서, 배포 후 Nginx 자체에서 잡는 방법
저는 이 방법에 대해서 설명해 보도록 하겠습니당
방법은 원하시는 걸로 편하게 선택해 주시면 됩니다~!@
✅ Nginx로 CORS 설정하기
💬 과정의 간략한 개요
ec2 접속
sudo vim /etc/nginx/sites-available/default 명령어로 설정 파일 열기
상황에 맞게 설정파일에 코드 추가하기
sudo systemctl restart nginx 명령어로 nginx 설정 수정했으니 restart ! 4. (꼭. 제발. 반드시.)
(+) systemctl 에 대해서 한 번씩 공부해보면 좋습니다!!!!
💡 잠깐! Proxy 란?
프록시(Proxy)란, '대리', '대신'이라는 뜻을 가지며, 클라이언트(사용자)가 서버에 직접 연결하지 않고 중간에 위치한 프록시 서버를 통해 간접적으로 연결하는 방식입니다.
클라이언트와 서버 사이에서 대리로 통신을 수행하는 것을 Proxy라고 하며, 이 중계 기능을 하는 주체를 Proxy Server 라고 합니다.
주로 사용자의 신원을 숨기거나, 보인 및 성능 향상을 위해 사용하게 됩니다!
포워드 프록시
클라이언트가 직접 접근할 수 없는 외부 서버에 접근할 수 있도록 중개하는 프록시 서버입니다.
리버스 프록시 (Nginx)
서버의 입장에서 클라이언트의 요청을 대신 받아 백엔드 서버로 전달하고, 백엔드 서버의 응답을 클라이언트에게 반환하는 방식
→ 클라이언트의 요청을 백엔드 서버로 프록시하면서, 원래 클라이언트의 IP 주소 및 요청 정보를 유지하여 백엔드 서버가 이를 인식하고 처리할 수 있도록 하는 것!
location / : nginx 서버가 루트 URL(/)로 들어오는 모든 요청에 대해 이 블록 안의 설정을 적용하도록 지정한다.
proxy_pass $service_url; : proxy_pass 지시어는 들어오는 요청을 지정된 URL로 전달한다. 여기서 $service_url은 실제 프록시하려는 백엔드 서버의 주소를 변수로 설정한 것이다. 예를 들어, $service_url이 http://sopt로 설정되어 있다면 모든 요청이 http://sopt로 전달된다.
proxy_set_header X-Real-IP $remote_addr; : 이 지시어는 프록시 서버가 원래 클라이언트의 IP 주소를 백엔드 서버로 전달하기 위해 HTTP 헤더 X-Real-IP를 설정한다. $remote_addr는 요청을 보낸 클라이언트의 실제 IP 주소를 나타낸다. 이를 통해 백엔드 서버가 실제 클라이언트의 IP 주소를 알 수 있다!
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
: 이 지시어는 X-Forwarded-For 헤더를 설정하여 요청이 지나온 모든 프록시 서버의 IP 주소를 포함하는 목록을 전달합니다. $proxy_add_x_forwarded_for는 현재 클라이언트의 IP 주소와 기존의 X-Forwarded-For 헤더 값을 합쳐줍니다. 이를 통해 백엔드 서버는 요청이 어떤 경로를 통해 왔는지 추적할 수 있다.
proxy_set_header Host $http_host; : 이 지시어는 Host 헤더를 설정한다. $http_host는 클라이언트가 요청한 호스트명을 나타낸다. 이는 원래 요청의 호스트 헤더를 백엔드 서버로 그대로 전달하는 역할을 한다. 이를 통해 백엔드 서버는 원래 클라이언트가 어떤 호스트로 요청했는지 알 수 있다.
오랜만에 다시 정리하며 복습하는 시간이 되었던 이번 이슈 ..
CORS (Cross Origin Resource Sharing)
한 사이트에서 주소가 다른 서버로 요청을 보낼 때 주로 접하게 되는 오류입니다.
웹과 협업을 할 일이 있다면, 반드시 알고 넘어가야 하는 부분 !!!
✅ 출처(Origin)
이 3가지가 같은 경우,
동일 출처(Origin)
다른 경우에교차 출처(Cross-Origin)
가 됩니다.출처(origin): 요청을 보내는 웹사이트와 요청을 받는 API 서버의 주소를 말합니다.
✅ 쉽게 알아보는 CORS란?
브라우저는 사용자가 접속한 웹사이트와 다른 출처(도메인, 포트, 프로토콜)를 가진 리소스에 접근하려고 할 때, 이 요청을 허용할지 말지를 결정합니다. 즉, 내가 만든 웹사이트aaa.com가 다른 도메인(예: bbb.com)의 API에 데이터를 요청할 때, 브라우저는 이를 차단할 수 있습니다.
💬 왜 차단될까?
브라우저는 ‘보안’을 위해 사용자가 방문한 웹사이트aaa.com 외부의 다른 사이트를 완전히 신뢰하지 않기 때문입니다. 특히, 사용자 정보나 자원을 무단으로 접근하는 것을 막기 위해 이런 제한이 걸려 있습니다.
💬 하지만, Postman이나 서버에서 같은 요청을 보내면 통과된다! 왜 그럴까?
Postman이나 백엔드에서는 CORS 정책을 따르지 않기 때문입니다. CORS는 오로지 브라우저(크롬, 엣지, 사파리같은 프론트엔드)가 적용하는 보안 정책이기 때문에 서버 사이에서는 아무런 문제 없이 데이터를 주고받을 수 있습니다.
💬 로그인이 유지되는 원리?
로그인이 유지되는 원리는 보통 브라우저에 저장된 인증 정보(예: 쿠키 🍪) 덕분입니다.
예를 들어,
🚫 그런데! 만약 범죄자들이 나쁜.com이라는 사이트를 만들어 내 정보를 빼내려 한다면 어떻게 될까요?
내가 나쁜.com 에 접속하게 되면, 그 사이트의 HTML, CSS, JavaScript 코드가 내 브라우저에 로드됩니다.
이 코드로 인해 범죄자들이 브라우저에서 sopt.com의 쿠키와 같은 인증 정보를 사용하여 sopt.com서버에 악의적인 요청을 보낼 수 있는 상황이 발생할 수 있습니다.
예를 들어, 나쁜.com이 sopt.com에 나의 개인정보 조회 요청을 보내고, 그 응답 데이터를 탈취하여 자신의 서버로 전송할 수 있습니다.
→ 이처럼 브라우저에 저장된 정보가 사용자의 의지와 무관하게 악용될 수 있기 때문에, **SOP(Same-Origin Policy, 동일 출처 정책)**이라는 보안 정책이 이를 방지합니다. 동일 출처 정책은 오직 동일한 출처(Origin)에서만 데이터를 접근할 수 있도록 제한하여, 외부 출처에서 무단으로 데이터를 가져가는 것을 막습니다. (기본적으로 브라우저는 SOP 를 따릅니다.)
🐰 오늘 우리가 알아볼 **CORS(Cross-Origin Resource Sharing)**는 동일 출처 정책에 대해서 예외를 허용하는 방식! 브라우저의 개발자 도구에서 “CORS 오류”가 발생할 경우, 이는 “해당 요청을 허용하려면 CORS를 설정하라”는 의미로 이해하면 됩니당~ 저희 서버가 꼭 해 주어야 할 작업이에요!
(ex) sopt.com에서 네이버 지도 API를 호출하려 할 때, 이 둘은 서로 다른 출처이기 때문에 기본적으로 리소스 요청이 차단됩니다. 이처럼 서로 다른 출처에서 리소스를 주고받는 것은 디폴트로 허용되지 않습니다. 이를 가능하게 해주는 것이 바로 CORS !
✅ 좀 더 깊게 알아볼까? CORS란?
CORS 의 동작 방식을 조금 더 깊게 살펴봅시다!
💬 CORS 요청 과정
브라우저는 다른 출처로 요청을 보낼 때 Origin 이라는 헤더(받는 쪽의 IP 주소, 사용할 프로토콜이나 옵션 등의 정보가 담김)를 자동으로 추가
요청을 받은 네이버 지도 API 서버는 응답할 때 헤더에 Access-Control-Allow-Origin을 포함하여 보냅니다. 서버에 sopt.com이 허용된 출처로 등록되어 있다면 이 값이 응답 헤더에 포함됩니다.
토큰 등의 사용자 식별 정보가 담긴 요청에는 더 엄격하다!
지금 설명한 방식은 Simple Request라고 해서
GET,
POST
등의 기본 요청에 사용되는 것입니다. 이 경우 브라우저는 추가적인 검증 없이 요청을 바로 전송합니다.PUT
,DELETE
등 처럼 서버의 데이터를 변경할 가능성이 있는 요청에는 사전 확인이 필요하겠죠?→ 브라우저는 본 요청을 보내기 전에 OPTIONS 메서드로 서버에 Preflight Request을 보내서, 본 요청을 허용할지를 검증합니다.
✅ CORS에서 보내는 요청들은 2가지의 종류!
1️⃣ Simple Request
2️⃣ Prefighted Request
OPTIONS
메서드를 사용해 서버에 “이 요청을 보내도 될까요?”라고 먼저 물음 → 이후, 서버가 해당 요청을 허용한다고 응답 시 → 실제 요청이 보내짐+++
BUT,,,,, Simple Request로 보내는 요청도, 서버가 CORS 설정을 신경 쓰지 않거나 보안 조치를 충분히 하지 않으면 서버에 저장된 데이터에 변경이 가해질 수 있기 때문에, 무조건적으로 SOP만 믿을게 아니라 서버 측에서도 그런 것들을 고려해 보안 설정을 철저히 하는 등 안전하게 프로그래밍 해야합니다!!
✅ CORS의 처리 방법
방법은 원하시는 걸로 편하게 선택해 주시면 됩니다~!@
✅ Nginx로 CORS 설정하기
💬 과정의 간략한 개요
sudo vim /etc/nginx/sites-available/default
명령어로 설정 파일 열기sudo systemctl restart nginx
명령어로 nginx 설정 수정했으니 restart ! 4. (꼭. 제발. 반드시.)(+)
systemctl
에 대해서 한 번씩 공부해보면 좋습니다!!!!💡 잠깐! Proxy 란?
프록시(Proxy)
란, '대리', '대신'이라는 뜻을 가지며, 클라이언트(사용자)가 서버에 직접 연결하지 않고 중간에 위치한 프록시 서버를 통해 간접적으로 연결하는 방식입니다.클라이언트와 서버 사이에서 대리로 통신을 수행하는 것을 Proxy라고 하며, 이 중계 기능을 하는 주체를
Proxy Server
라고 합니다.주로 사용자의 신원을 숨기거나, 보인 및 성능 향상을 위해 사용하게 됩니다!
프록시(Proxy)란??
💬 기존 loction{ } 내용
이
nginx
설정 파일의 내용은proxy_pass
지시어를 사용하여 요청을 다른 서버로 전달하는 프록시 서버 설정을 나타냅니다.즉, 이 설정 파일의 목적은
→ 클라이언트의 요청을 백엔드 서버로 프록시하면서, 원래 클라이언트의 IP 주소 및 요청 정보를 유지하여 백엔드 서버가 이를 인식하고 처리할 수 있도록 하는 것!
location /
:nginx
서버가 루트 URL(/
)로 들어오는 모든 요청에 대해 이 블록 안의 설정을 적용하도록 지정한다.proxy_pass $service_url;
:proxy_pass
지시어는 들어오는 요청을 지정된 URL로 전달한다. 여기서$service_url
은 실제 프록시하려는 백엔드 서버의 주소를 변수로 설정한 것이다. 예를 들어,$service_url
이http://sopt
로 설정되어 있다면 모든 요청이http://sopt
로 전달된다.proxy_set_header X-Real-IP $remote_addr;
: 이 지시어는 프록시 서버가 원래 클라이언트의 IP 주소를 백엔드 서버로 전달하기 위해 HTTP 헤더X-Real-IP
를 설정한다.$remote_addr
는 요청을 보낸 클라이언트의 실제 IP 주소를 나타낸다. 이를 통해 백엔드 서버가 실제 클라이언트의 IP 주소를 알 수 있다!proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
: 이 지시어는
X-Forwarded-For
헤더를 설정하여 요청이 지나온 모든 프록시 서버의 IP 주소를 포함하는 목록을 전달합니다.$proxy_add_x_forwarded_for
는 현재 클라이언트의 IP 주소와 기존의X-Forwarded-For
헤더 값을 합쳐줍니다. 이를 통해 백엔드 서버는 요청이 어떤 경로를 통해 왔는지 추적할 수 있다.proxy_set_header Host $http_host;
: 이 지시어는Host
헤더를 설정한다.$http_host
는 클라이언트가 요청한 호스트명을 나타낸다. 이는 원래 요청의 호스트 헤더를 백엔드 서버로 그대로 전달하는 역할을 한다. 이를 통해 백엔드 서버는 원래 클라이언트가 어떤 호스트로 요청했는지 알 수 있다.💬 CORS 설정한 location{ } 내용
자신의 프로젝트의 상황에 맞게 아래 내용들을 커스텀하여 설정해 주시면 됩니다!
Simple Requset 관련해서 조금 살펴보자면,,,,
'Access-Control-Allow-Origin' '{허용할 도메인}'
→ 일단 전체 ‘*’ 로 열어두었습니다.
'Access-Control-Allow-Methods' '{허용할 Method들}'
'Access-Control-Allow-Headers' ‘…’
Preflight, Credential 요청에 대해서도 더 자세하게 알고싶다면 ..
🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏
💬 근데, 그럼 단일 도메인만 열어주는 거 가능해요??
|
’또는’ 조건을 사용하여 여러개의 출처를 허용해 줄 수 있습니다~이 출처 중 하나와 일치한다면 $cors 변수 값을 true 로 설정해 주게 되고, location 블록 내에서 $cors 변수를 확인해서 CORS 헤더를 설정해 주면 뚝딱입니다.
그래도 잘 모르겠다면 여기를 참고해 주세용!
공식문서
https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
The text was updated successfully, but these errors were encountered: