본문 바로가기
  • 오늘도 한걸음. 수고많았어요.^^
  • 조금씩 꾸준히 오래 가자.ㅎ
IT기술/CS(ComputerScience)

[CS] SOP CORS 웹 개발에서 알아두면 좋은 내용

by 미노드 2024. 4. 11.

예전에는 출처(프로토콜, 호스트명, 포트)가 다르더라도 ajax 통신을 수행할 때 요청과 응답이 문제없이 가능했습니다.
하지만 이러한 방식에는 보안에 취약하다는 문제가 생길 수 있습니다.

Cross-Site Scripting (XSS)
1. 사용자의 쿠키 정보를 가져오는 자바스크립트 코드(악성코드)를 포함한 게시글을 작성한다.
2. 어떤 사용자가 로그인하면 쿠키에 그 정보가 저장됨
3. 해커가 작성해둔 게시글을 사용자가 클릭했을 때 악성코드가 작동
4. 쿠키에 저장된 사용자 정보가 해커의 웹사이트에 전송됨

Cross-site request forgery (CSRF) - 사이트 간 요청 위조
1. 사용자가 보안이 취약한 서비스에 로그인 한다.
2. 사용자 정보가 쿠키에 저장된다.
3. 해커가 만든 피싱 사이트에 접속한다. (클릭 유도, 위조된 광고 등을 통해)
4. 해커가 원하는 대로 사용자 정보가 바뀐다.

서로 다른 출처에서도 서버 요청과 응답이 가능하다는 게 원인이기 때문에
브라우저는 보안성을 증가시키기 위해 서로 다른 출처의 요청을 불가능하게 만드는 방식을 도입했습니다.
이게 SOP(동일 출처 정책)입니다.

SOP(same-origin-policy) 

동일 출처 정책은 WEB App이 같은 출처에서만 자원을 공유하는것을 원칙으로 합니다.
URL의 프로토콜, 포트, 호스트가 모두 같을 때 Same Origin으로 판단하고 자원 요청을 허용 합니다.

프로토콜은 앞서 말한 http / https 를 말하며 호스트는 사이트의 주소를 말합니다. (https://tistory.com)
포트는 호스트 뒤에 붙는 포트 번호를 말합니다.
이들이 모두 같을 때 데이터를 읽어 올 수 있도록 규제합니다.

같은 출처 VS 다른 출처

- 참고 : https://beomy.github.io/tech/browser/cors/

같은 출처인지 다른 출처인지 이해를 돕기 위해 예제를 정리해보면 다음과 같습니다.

https://teck10.tistory.com/mainview 같은 출처 Protocal, Host, Port 동일
https://teck10.tistory.com/mainview?q=work 같은 출처 Protocal, Host, Port 동일
https://teck10.tistory.com/mainview#work 같은 출처 Protocal, Host, Port 동일
http://teck10.tistory.com 다른 출처 Protocal 다름
https://teck10.tistory.com:8081/mainview 다른 출처 Port 다름
https://teck12.tistory.com/mainview 다른 출처 Host 다름

 

하지만 SOP 규제가 완화된 경우가 두 가지가 있습니다.

첫번째는 <img>, <style>, <script>의 태그입니다.
해당 태그들의 src 혹은 onerror와 같은 조건에 동일 출처가 아닌 URL을 넣어도 규제하지 않으며 외부에서 참조가 가능합니다.

두번째는 교차 출처 리소스 공유(CORS)입니다.

Cross-Origin Resource Sharing의 약어이며, 다른 출처의 데이터를 사용해야 하는 경우도 있기 때문에 CORS와 관련된 HTTP 헤더를 서버측에서 추가해 전송합니다.
클라이언트에서 CORS 헤더를 설정해 요청하면, 수신측에서 헤더를 맞게 구분해서 규칙에 맞는 헤더를 추가해 응답합니다.

CORS는 아래 3가지의 동작 방식을 갖습니다.

  • 간단한 요청 (Simple Requests)
  • 사전 요청 (Preflight Requests)
  • 인증을 이용하는 요청 (Credential Requests)

1. 간단한 요청

간단한 요청, Simple Requests는 기존 데이터를 손상시키지 않을 요청들에 의해서만 가능합니다.
만약, DELETE나 PATCH요청과 같은 요청을 누구나 간단하게 요청해서 처리할 수 있다면, 요청하나만으로도 서버에 있는 데이터를 모두 지운다던가 이상하게 변경 할 수 있을 것입니다.

따라서 Simple Requests는 아래의 조건을 만족할때만 가능합니다.

  • GET, HEAD, POST중 한가지 요청일 것
  • Custom Header가 존재하지 않을 것
  • POST일 경우, Conent-Type이 application/x-www-form-urlencoded, mutipart/form-data. text/plain 중 하나일 것

사실상 요즘은 대부분 API요청을 application/json을 통해서 보내기 떄문에 Simple Requests는 잘 사용되지 않습니다.

2. 사전 요청 Preflight Requests

사전요청은 본 요청을 보내기전에 사전 요청을 보내서 서버가 이에 대해서 응답이 가능한지를 확인하는 방법입니다.
요청들은 서버에 있는 데이터를 손상시키거나 변조시킬 위험이 있는 코드를 보낼 수 있습니다.
사전요청으로 먼저 서버에게 해당 요청을 진행가능한지 확인 후, 해당 요청을 처리하는 방식입니다.

아래 그림처럼 Access-Control-Allow-Origin 이라는 헤더에 정보를 담아 브라우저에 보내줍니다.
브라우저는 아래 헤더를 확인 후 이상이 없으면 다시 요청 실행, 이상 있으면 CORS 에러를 냅니다.

참조 - https://learnote-dev.com/java/Spring-CORS%EC%9D%B4%EC%8A%88-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0/

 

[Spring] CORS 설정하기

서론 저는 지금 간단한 토이 프로젝트를 하나 진행중인데요.

learnote-dev.com

 

CORS 에러 해결 방법

CORS 에러 외부 API 서버에서 데이터를 가지고 올 때 헤더에 접근을 허락하는 내용이 없으면 발생합니다.
브라우저에서 확인할 수 있으며 어떻게 해결하면 좋을까요?

CORS기능을 끄는건 선택지도 있겠지만, 좋은 선택은 아닐 것입니다.
CORS는 브라우저 보안 정책이므로 서버에서 서버로 요청 시 CORS 이슈가 발생하지 않습니다.
이 방식을 통해 간단히 해결할 수 있는데, 
프록시 역할을 할 수 있는 중간 서버를 활용해서 통신하는 것도 방법이 될 수 있습니다.

또는 요청 서비스마다 CORS에러가 나지 않도록 서버측에서 헤더를 지원해주는 것도 방법입니다.
이를 위해 브라우저에서 요청 헤더를 포함해서 요청하고 서버에서도 이를 응답합니다.

  • Access-Control-Request-Headers : POST
  • Access-Control-Request-Method : X-PINGOTHER, Content-Type
  • Access-Control-Allow-Origin : http://foo.example
  • Access-Control-Allow-Methods : POST, GET, OPTIONS
  • Access-Control-Allow-Headers : X-PINGOTHER, Content-Type
  • Access-Control-Max-Age : 86400

해당 설정에 맞는조건이면, 브라우저에서 CORS 에러를 내지 않습니다.
다만 여러 요청으로 테스트를 해보며 조절하는게 필요합니다.