[django] Same origin policy, Cross origin resource sharing

mquat·2022년 3월 12일
0

프로젝트를 위해 django 초기 세팅을 할 때, cors-headers를 추가하게 된다. cors가 무엇인지, 그리고 same origin policy가 무엇인지 정리했다.


django 초기 셋팅 때, 아래와 같이 CORS 설정해야 한다.

##CORS
CORS_ORIGIN_ALLOW_ALL=True
CORS_ALLOW_CREDENTIALS = True

CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
)

CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
)

CORS는 'cross origin resource sharing'의 약자다. 웹 상 존재하는 여러 policy 중 하나. (위키백과에서는 '교차 출처 리소스 공유'라고...)

일단 origin 의 뜻은, '출처'다. 웹 상에서 정의하는 출처는:
접근할 때 사용하는 URL의 scheme(프로토콜), 호스트(도메인), 포트로 정의한다. 만약 2개의 url이 있고 위 3가지 요소가 모두 일치하는 경우 같은 출처를 가졌다고 말한다. (출처: MDN)

아래와 같이 2개 url은 같은 출처를 갖는다.
1) https://example.com > http의 기본 port는 80으로, 생략 가능
2) https://example.com:80

아래의 2개는 다른 출처를 갖는다.
1) https://example.com > port: 80
2) https://example.com:8080 > port: 8080

아래의 2개도 역시 다른 출처다. (다른 프로토콜)
1) http://example.com
2) https://example.com


origin 제한과 관련된 정책이 2가지가 있는데,
그것이 SOP (same-origin policy)CORS(Cross origin resource sharing)이다.

SOP는 같은 출처 상에서만 리소스를 공유할 수 있다는 정책이다. 이러한 정책이 필요한 이유는, 웹 어플리케이션들은 기본적으로 외부 침입에 취약하기 때문. 만약 어떤 사용자가 관리자가 아님에도 불구하고 악성 스크립트를 삽입하고 어플리케이션이 제대로 검사하지 않은 채 사용한다면 주요 정보들이 새나갈 것이다. (XSS나 CSRF)

하지만 다른 출처라 해도 리소스를 공유할 수 있는 예외 상황이 있는데, 그 중 하나가 CORS를 준수했을 때이다.

그런데 origin 비교는 클라이언트가 진행한다.
그러니까 일단 서버에 요청하면, 서버는 CORS 등과 상관없이 request에 대한 response를 하고, 이것이 CORS를 준수했는지 아닌지는 웹 브라우저가 판단한다. 그래서 CORS 에러가 떴건 말건, 서버 상에서는 response 완료 라는 로그만 남는다. 그래서 CORS를 이해하고 이를 적용하는 것이 중요하다.

이미지 출처: https://www.keycdn.com/support/cors#http-response-headers

CORS 요청이 가능하려면, reqeust header/response header에 관련 셋팅을 해야 한다.
예를 들어, domainx.com 에서 domainy.com에게 리소스 요청을 한다고 가정하자.
그러면 domainx.com 의 요청 header에는 아래 내용이 포함된다.

Origin: http://domainx.com

domainy.com은 아래와 같은 내용을 header에 포함해 응답한다.

Access-Control-Allow-Origin: http://domainx.com (혹은 *)

그러면 domainx.com은 CORS정책에 따라 access가능한 origin 정보를 확인 후 리소스 접근 여부를 판단한다. 위의 경우, domainx.com은 접근 가능하다고 셋팅되어 있으므로 리소스를 불러올 수 있다.


그런데 위와 같은 사례는 아주 단순하게 보여준 사례고, 실제로는 더 많은 정보를 주고 받으면서 CORS 위반 여부를 확인한다. 그리고 더 복잡한 요청-응답이 이뤄지는 대부분의 경우 preflight (예비 요청)이 먼저 이뤄진다. 브라우저 스스로 이 요청이 안전한 요청인지 유효성을 검사하는 것이다. 이 경우에 해당하는 시나리오는 3가지:

  • http 메소드에 GET, POST 외 다른 메소드가 포함된 경우
  • 사용자 정의 header (custom header)가 포함된 경우
  • content-type, 즉 body에 포함된 MIME가 text/plain(일반 텍스트 포맷)이 아닌 다른 타입인 경우

preflight 요청을 할 때는 아래 예시와 같이 request header가 작성된다.
(OPTIONS 라는 메소드 사용해서 요청을 보냄)

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

response header는 아래와 같다.

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
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
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

In a nutshell...
CORS 관련 셋팅은 front-back 양측에게 중요한 일이다. 그래서 django 초기 셋팅 시, 허용하는 origin / method / header를 포함하는 것은 반드시 필요하다.

📌추가 용어

  • MIME (Multipurpose Internet Mail Extensions)
    • 전자우편 이메일 표준 포맷
    • SMTP는 7비트 ASCII 문자를 사용하나, 8비트 이상의 코드를 사용하는 문자나 binary(이진) 파일(이미지, 영상 등)들은 MIME 포맷으로 변환되어 SMTP로 전송 가능
    • (updated 220808)기존에는 ASCII 기준으로 인코딩되어 텍스트 전송이 이뤄졌으나, 이것만으로는 이미지/영상 등의 binary 파일을 주고받는데 한계가 있어 MIME을 통한 인코딩/디코딩이 필요해진 것 (인코딩: binary -> text, 디코딩: text -> binary)
    • Content-Type, Content-Transfer-Encoding 등의 header를 정의함
  • CSRF (Cross site request forgery)
    • 공격자의 특정 웹사이트 대상 의도한 행위(수정,삭제 등)를 사용자가 실행하도록 만드는 것
    • 서버에 공격을 가하는 것
    • 다음과 같은 process로 공격이 이뤄짐
      1. 사용자가 특정 웹사이트 로그인함
      2. 공격자는 공격용 페이지를 게시판/이메일 등의 경로를 통해 전달
      3. 사용자가 공격용 페이지를 열면, 브라우저 또한 이를 오픈하면서 공격 완료
    • 실제 사례 (2008년 옥션에 등록된 1,800만건 개인정보 해킹)
      1. 옥션 관리자 중 한 명이 회사에서 작업하던 중 한 메일을 조회함
      2. 그 메일에는 공격자의 코드(url)가 담긴, 공란으로 보이는 이미지 파일이 숨겨져 있었음

      3. 옥션 관리자가 이메일을 열면 이미지 파일을 열기 위해 그 안에 포함된 코드가 같이 열림
      4. 관리자의 계정이 공격자가 원하는 대로 변경됨 (id:admin / pw: admin)
  • XSS (Cross site scripting)
    • 공격하려는 웹사이트에 특정 스크립트를 삽입하는 것으로, 클라이언트를 대상으로 공격
    • reflected XSS / stored XSS가 있음
    • reflected XSS는 스크립트가 삽입된 url을 노출시켜 접속 즉시 자바스크립트 실행하는 방법
    • stored XSS는 스크립트를 서버에 저장시켜 (게시글, 댓글 등) 사용자가 클릭하면, 해당 스크립트가 포함된 응답이 사용자에게 전달됨
    • 공격 process (대부분 stored XSS로, reflected XSS는 브라우저에서 차단 가능)
      1. 공격자는 공격할 사이트에 스크립트를 심는다.
      2. 사용자가 해당 페이지에 접속하면, 쿠기/세션 토큰 등의 정보가 공격자 홈페이지로 넘어감

(220315 update) XSS를 정리하면서도 약간 공격 형태가 모호해서, 영상을 찾아봤는데 생활코딩에 좋은 영상이 있었다. 보면서 좀 더 이해하는데 도움이 되었음.

참고 자료
https://developer.mozilla.org/ko/docs/Glossary/Origin#다른_출처의_예제
https://www.keycdn.com/support/cors#http-response-headers
https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/OPTIONS
https://evan-moon.github.io/2020/05/21/about-cors/
https://ko.wikipedia.org/wiki/MIME#Content-Type
https://4rgos.tistory.com/1

profile
예비 개발자의 기술 블로그 | explore, explore and explore

0개의 댓글