ASAC 07기 : 24.12.19 웹 브라우저와 웹 서버의 저장소 및 HTTPS, CORS 보안

2SEONGA·2024년 12월 27일
2

ASAC

목록 보기
5/13
post-thumbnail

웹 브라우저 내 저장 : 1) Cookie = 팔찌

HTTP의 기본 특성 : Stateless = 누가 요청한 지 모름

  • 기본적으로 세션을 유지하지 않고, 서버는 Client-specific 세션 데이터를 저장하지않기에 HTTP는 매 요청이 어떤 웹 브라우저가 보낸 것인지 알 수 없음 (서버가 어디에도 저장하지 않음)

Stateful(서버) vs. Stateless(웹 브라우저)

  • Stateless 불연속성 웹 서버 입장에서는 매 요청이 어떤 웹 브라우저가 보낸 것인지 알 수 없음 ← HTTP
    • 최소한의 자원으로 서버 유지를 가능하게 함 (Easier to scale, cache, and manage the service)
      • 수억명의 트래픽(Concurrent Users) 커버 가능
    • 기본적으로 세션을 유지하지 않고, 서버는 Client-specific 세션 데이터를 저장하지않기에
      • 클라이언트가 세션을 유지하기 위해선 authentication tokens, credentials 등을 저장해야한다.
      • 클라이언트는 끊임없이 자신이 누구임을 밝혀야한다는것이 후에 배울 JWT 가 Stateless 인 이유 : 인증 정보가 웹 브라우저에 있기 때문
  • Stateful 연속성
    웹 서버가 이전에 요청받았던 웹 브라우저와 현재 요청의 웹 브라우저를 구별
    • 어떤 유저의 (어떤 웹 브라우저의) 요청인지 알 수 있다면
      • 요청마다 별개의 작업 수행 혹은 결과 반환 가능
      • 서버가 여러 개일 경우 어떤 서버를 호출해도, 서버에 장애가 생기더라도 다른 서버가 역할을 대신
    • ex) 로그인 계정 정보

서버는 웹 브라우저의 요청이 어떤 유저에 의해 요청된 것인지 알기위해 응답 반환시 요청자 정보를 함께 반환

  • 웹 브라우저는 응답을 받아, 응답 헤더에 붙어있던 요청자 정보웹 브라우저 쿠키에 저장
  • 웹 브라우저는 이후 요청부터 웹 서버에게 요청자 정보를 함께 전달하여 웹 서버는 누구의 요청인지 식별 가능
    - 요청자 정보 : 어떤 웹 브라우저가 요청했는지 인지 가능한 정보
    - 로그인한 계정 정보

요청자 정보 를 어디에 저장하는지에 따라 다른 방법론 : Cookie 혹은 Session

  • 웹 브라우저에 저장 : Cookie (클라이언트 측)
    • 쿠키는 어떤 값이든 가능하나, 일반적으로 노출 방지를 위해 인간이 이해할 수 있는 형태가 아닌걸로
  • 웹 서버에 저장 : Session (서버 측, 쿠키를 안쓰는게 아니라 웹 브라우저 쿠키에 SESSION_ID 를 저장)
    • 웹 브라우저에 저장할 수 없을 정도로 크거나 복합적인 정보인 경우
    • 웹 브라우저에 저장할 수 없는 민감 정보인 경우 → 즉, 로그인 정보 혹은 기타 정보를 서버에 저장하는 것

  • 웹 서버가 웹 브라우저에게 최초로 전달해줄 때 : 웹 서버 응답(Response)의 헤더 Set-Cookie 로 전송

  • 웹 브라우저가 그 이후로 웹 서버에게 전달할 때 : 웹 브라우저 요청(Request)의 헤더 Cookie 로 전송

Cookie = 웹 서버의 제어 + 웹 브라우저 내 저장 및 전송

웹 서버의 제어 = Set-Cookie 헤더를 통해 어떤 데이터를 쿠키로 쓸 것인지, 유효시간 및 보안 설정

  • 웹 브라우저가 쿠키를 웹 서버에게 전송하는 기준 (전송할지, 말지) = 해당 쿠키를 어떤 요청에 보낼지
  • 모든 쿠키에는 도메인이 연결됨
    • 예) 웹 브라우저 내 저장되어있는 쿠키 리스트
      • 1번 쿠키 : h1 = w1 (Domain: a.com, Path: /) → 즉, /**
      • 2번 쿠키 : h2 = w2 (Domain: a.com, Path: /user)
      • 3번 쿠키 : h3 = w3 (Domain: b.com, Path: /hello)
      • 4번 쿠키 : h4 = w4 (Domain: c.com, Path: /world)
    • 예) 위 리스트 기반으로 아래 웹 서버에 대한 요청에 따라 전송되는 쿠키 예
      • 웹 브라우저에서 a.com/user/name 호출 시 1번 쿠키 + 2번 쿠키 전송
      • 웹 브라우저에서 a.com/ 호출 시 1번 쿠키 전송
      • 웹 브라우저에서 b.com/hello 호출 시 3번 쿠키 전송
      • 웹 브라우저에서 c.com/ 호출 시 어떤 쿠키도 전송하지 않음

  • 웹 서버가 브라우저에게 최초 응답 반환 시 Set-Cookie 헤더에 원하는 쿠키 설정 및 값을 전달

  • Set-Cookie 로 반환된 쿠키값들이 웹 브라우저에 잘 저장되어있는지 확인

  • 이 쿠키들을 웹 브라우저가 그 다음부터 웹 서버에게 요청 시 잘 보내지는지 확인

  • 쿠키 유효시간 : Session Cookie 는 창을 닫았다가, 다시 키면 사라져있음
  • 명시되어 있다면 : Persistent Cookie (지속 쿠키)

  • 명시되어 있지 않다면 : Session Cookie (세션 쿠키)

    • 잠깐, Session 의미 : 열고(connect) → 닫힘(disconnect) 의 하나의 Pair 에 모두 사용

      Session 이란, 결국 열고 닫는 것

    • 몇 가지 예시로 살펴보자

      • 로그인 세션 : 로그인한 뒤 → 로그아웃하기까지
      • HTTP 세션 : TCP/UDP 연결 후 Request 전송 후 Response 받기까지
      • 브라우저 세션 : 하나의 탭/창이 열리고 닫히기까지

Cookie에서의 보안의 중요성

: 유저 로그인 인증을 위한 정보 저장이나 웹앱에서 광고 및 마케팅 목적을 위한 식별자로 사용되는 기술로
웹 브라우저에 저장되어 있어서 쿠키 조회가 가능하고, 웹 브라우저가 웹 서버에 요청 시 탈취도 가능

  • HttpOnly : XSS(자바스크립트) 공격에 의한 쿠키 접근 제어

  • Secure : 패킷 탈취(Man-in-the-Middle) 방지를 위해 HTTPS 채널에서만 사용

    MITM 방지 : 요청(클라이언트)-응답(서버) 사이에서 요청, 응답 탈취

    • Man-in-the-Middle
  • SameSite : 웹 브라우저 주소란에 표시된 도메인과 동일한 도메인에 대한 요청(API)시에만 쿠키 전송

    CSRF 방지 : 유저가 의도하지 않았는데, 해커가 심은 스크립트에 의해 크로스 사이트에 요청 전달

    • Cross-Site Request Forgery 사이트 간 요청 위조
      • 동일 사이트(Same Site) 정의 : www.**web.dev**static.**web.dev**
      • 크로스 사이트(Cross Site) 정의 : www.**web.dev** ≠ static**.another.com**
      • 과거 해당 크로스 사이트에 접속해서 얻은 로그인 인증 정보가 함께 전달돼 크로스 사이트 (비의도) 공격
        • CSRF 공격으로 크로스 사이트 (비의도) 요청 시 크로스 사이트에 과거에 설정됐던 쿠키가 전송
        • 크로스 사이트에 과거에 설정됐던 쿠키 = 서드파티 쿠키
        • SameSite 옵션 이해를 위한 중요 개념 : 퍼스트파티 쿠키 & 서드파티 쿠키 설명 및 예시 그림
          • SameSite
            map.naver.com과 blog.naver.com → .naver.com으로 엮여있음
          • 퍼스트파티, 서드파티 판단은 Site Domain 과 Cookie Domain 의 일치여부로 결정
          • Site Domain : 현재 유저(내)가 보고있는 웹 브라우저창에 뜬 도메인명
          • Cookie Domain : 쿠키에 설정되어있는 Domain + Path 값에 명시된 도메인명
          • SameSite 옵션
            크로스 사이트인 경우, 크로스 사이트에 해당하는 쿠키라 할지라도 전송되지 않게 막을 필요

퍼스트파티 쿠키와 서트파티 쿠키

퍼스트파티 쿠키

Cookie Domain = Site Domain

현재 도메인에서 필요에 따라 생성/저장한 로그인 인증과 같은 개인화 정보 인식용 쿠키

서드파티 쿠키

Cookie Domain ≠ Site Domain

많은 홈페이지들을 오가며 유저의 행동을 기록, 추적하기 위한 Google Ads 정보 수집
  • HTTPS 사용해도 = 서드파티 쿠키가 로그인, 인증 정보를 담고있다면 어드민 API 호출도 가능
    • 전체 유저 정보 조회, 대량 삭제 등 권한이 필요한 API 호출이 인증정보 쿠키로 손쉽게 가능
  • HTTPS 미사용 시 = MITM 로 요청을 가로챈다면 서드파티 쿠키를 외부에서 볼 수 있음
    • 그래서 크로스 사이트 요청 시 크로스 사이트에 해당하는 쿠키라 할지라도 전송되지 않게 막을 필요
      • 보안 레벨 높음 - Strict : 퍼스트파티 쿠키 전송만 허용
      • 보안 레벨 중간 - Lax : 서드파티 쿠키라도 특수 케이스시엔 부분 허용
        • 보안 업데이트 후 최신 크롬 Default
        • 특수 케이스 = 상태 서버 변경하지 않고 조회만 :
          GET, <a href>, <link rel=”prerender”>
      • 보안 레벨 낮음 - None : 서드파티 쿠키 모두 허용
        • 보안 업데이트 전 과거 크롬 Default
        • 단, Secure 설정을 강제하여, HTTPS 미사용시 MITM 탈취에 대한 문제 방지
  • 개발자 모드 Application - Cookie 를 통해 HttpOnly 옵션 건드려보기
    • HttpOnly 를 통해 Javascript 로 document.cookie 호출 - 노출 여부 확인하기

  • 매번 브라우저에 요청 시 해당 도메인에 대해 저장되어있는 쿠키 전송
    • 이게 크로스 사이트일때 전송을 막을것인지 여부 : SameSite

  • None
    도메인 검증 과정이 없어 모든 도메인에서(서드파티 쿠키에서도) 쿠키를 전송하고 사용 가능
    사용자가 사이트 간 요청 위조(CSRF - Cross-site request forgery) 및
    의도하지 않은 정보 유출에 취약 → Secure 옵션 설정 (https만 접근 가능) 필요

  • Lax

    자사 도메인이 아니더라도(서드파티 쿠키여도) 일부 케이스에서는 접근 허용
    → 상태를 변경하지 않는 Get 요청만 허용

  • Strict

    자사 도메인에서의(퍼스트파티 쿠키의) 전송만 허용

변경 사유가 뭘까?

  1. 보안 및 개인정보 보호 문제
  2. 쿠키가 많아지면 Request에 오버헤드 발생

우리가 할 일

  • cross-site에서 쿠키를 사용할 수 있어야 하는 경우 (광고, 쿠키) → 쿠키 생성 시 samesite=none, secure 옵션 부여
  • 쿠키 생성 시 samesite=none만 있으면 secure 옵션도 부여
  • http 페이지에서 쿠키를 담아 https를 호출해야 하는 경우 → 호출 페이지를 https로 변경

Cookie Domain ≠ Site Domain

많은 홈페이지들을 오가며 유저의 행동을 기록, 추적하기 위한 Google Ads 정보 수집

  • 실제 현업에서의 퍼스트파티 쿠키와 서드파티 쿠키의 예시


웹 브라우저 내 저장 : 2) Storage = 저장소

Storage 는 Cookie, Session 처럼 Stateful HTTP 를 위한 기술은 아님

Storage (HTML5 표준) 등장 전에는 웹 브라우저 저장소는 유일하게 Cookie 만을 활용
Storage (HTML5 표준) 등장 후에는 웹 브라우저에서 아래 두 유즈케이스를 제대로 나눠 활용

  • Storage : 웹 브라우저 저장소
    • 유저에 의해 변경된 옵션 상태 등 → 필요에 따른 조회가 필요할때 (진짜 저장소)
      • 예) 마지막에 어떤 소셜 계정으로 로그인했는지 저장하고, 1년 뒤 로그인할때 표시하여 알려줌
  • Cookie : 웹 서버에게 웹 브라우저가 매번 전달할 특정 정보를 위한 저장소 (Stateful)
    • 로그인 인증 정보 등 → 웹 서버가 요청마다 필요한 정보를 웹 브라우저에 넣어두고 전달받아 씀
    • 생각해보기 : Storage 에 저장할까? Cookie 에 저장할까?
      • 사용자가 방문한 페이지를 저장 : Storage
      • 검색기록 : Storage
      • 장바구니 : Storage
      • 로그인 정보 저장 / 로그인 상태 유지 : Cookie
      • 유저에 의해 변경된 옵션의 상태 : Storage
  • Cookie : 웹 서버에게 반복적으로 전달하기 위한 + 작은 정보 + (만료 시간을 갖고)
  • Storage : 웹 브라우저에서만 사용가능한 + 큰 정보 + (만료 시간 없이)

Storage 의 종류 : Storage 유효 시간에 따라

  • Local Storage : 웹 브라우저 창이 닫혀도 영구적으로 저장 - 용량 처리 조심
  • Session Storage : 웹 브라우저 창이 닫히면 삭제

Storage 의 종류별 용례

  • 프론트엔드 개발자가 브라우저에서 무엇인가를 저장한다하면, Storage 를 쓸 것
    • 단발적인 내용은 Session Storage, 길게 저장해도되는 내용은 Local Storage
      • 예) 최근에 로그인했던 수단을 표기하기 위해 Local Storage 내 수단 저장

웹 브라우저에 저장된다는 의미에서는 쿠키와 스토리지는 동일하나, 목적과 세부적인 부분들이 상이

Cookie비교Storage
4KB저장 가능 용량10MB
만료 시간 설정 가능 (세션 : 임시저장)만료만료 시간 설정 불가능 (세션 : 임시저장)
지정된 Domain + Path 대해서만 유효범위지정된 Domain 내에 모두 유효

| 웹 서버에게 Non-HTTPS 요청 시 노출
스크립트 접근 여부 제어 가능 | 보안 | 웹 브라우저에서만 접근 가능
스크립트 접근 가능 |
| 브라우저간 공유 불가 →
추후 배울 Session 으로 해결 가능 | 공유 | 브라우저간 공유 불가 →
추후 배울 Session 으로 해결 가능 |


웹 서버 내 저장 : Session = DB 를 소유

Session → Cookie의 단점이 곧 Session의 장점

  • 웹 브라우저 쿠키에 저장하던 값을 웹 서버측에 저장하기 위해 별개의 저장소 DB 가 필요
    ⚠️ 주의 : Session 을 사용한다고, Cookie 를 사용하지 않는 건 아님
    • 웹 브라우저 내 Cookie 에는 어떤 세션인지 알기위한 ID 값 저장 필요
      • 웹 브라우저가 실종되면, Session 에 저장하고 있는 정보는 시간이 흐름에 따라 삭제 필요
        • 사용되지 않는 정보임에도 자리를 차지
        • 우리가 배운 Cache 의 임시 저장과 유사하게 기존 값을 버려야 용량을 효율적으로 사용
          • 저장소를 한정짓고 새값이 들어오면 과거의 값들을 버릴까? 시간에 따라 기존 값들을 없애줄까?
    • Session 의 대표적인 예는 웹 브라우저로부터 쿠키로 SESSION_ID 를 받아 해당 요청 유저의 정보 조회
      • 속도가 매우 중요 : API 수천 번의 호출마다 Session 조회 필요
        • 따라서 현업에서는 메모리 기반 DB 인 Redis 다수 사용
          • 메모리 중심 인스턴스의 비용 이슈 (비싼 메모리), 확장성 이슈 (비싼 인스턴스)
  1. 쿠키 정보가 웹 브라우저에 저장되다보니
    • 민감 정보들이 안전하지 않은 채로 저장되어있고 (HttpOnly, Secure, SameSite 방어는 가능)
    • 웹 브라우저간 공유 불가 : 웹 브라우저 단위의 저장소이다보니 지역성 문제
      • 각각의 웹 브라우저에서 한 행동들이 각각의 웹 브라우저에만 기록
  • Session정보를 웹 서버측에 저장
    • 민감 정보들이 웹 서버측에 안정적으로 저장
    • 웹 브라우저간 공유 가능 : 여러 웹 브라우저를 돌아다니며 행동해도 모두 서버에 중앙 기록
  1. 쿠키는 Domain + Path 만 일치한다면 해당 웹 서버로 모든 쿠키를 담아 보내다보니
    • 쿠키로 저장하려는 정보량이 많아질수록 → 요청 크기가 증가
      • 불필요한 Network Overhead : 비대해질수록 요청 사이즈도 증가
        • 쿠키를 단지 저장소로 써서는 안되는 이유
        • 웹 서버에게 알려주지 않아도 되는 정보의 경우 웹 스토리지 사용 권장
  • Session 은 정보를 웹 서버측에 저장하므로 정보 저장으로 인한 요청 방해 불가
    - 단, 매 요청마다 Session 저장소에 저장된 세션 정보 조회 필수 → 빠른 DB 인 Redis 고려할 것

웹 보안 : HTTPS (HTTP Secure, TLS) = 웹 통신 내 End-to-End 회선 보호

HTTPS 목적 → MITM (Man-In-The-Middle)

SSL(Secure Sockets Layer) 혹은 TLS(Transport Layer Security) 프로토콜을 통해 HTTP 보안 강화

요청을 보내고, 응답을 받는 두 주체(End-to-End)만 HTTP 요청 및 응답을 읽을 수 있게 암호화

  • 목적 : MITM (Man-In-The-Middle) 공격 방지
    • 심화 : MITM (Man-In-The-Middle) 공격 종류
      • 스니핑(Sniffing, 도청) : Wireshark 를 통해 여러분의 모든 웹 서핑 패킷 도청 가능
      • 패킹 주입(Packet Injection) : DHCP/ARP 로 LAN 내 컴퓨터 인지 후 패킷 대신 받아 조작 주입
        • ARP를 통해 해커 MAC 주소로 LAN 내 컴퓨터 인지
          • Spoofing 위변조 (혹은 아기돼지 삼형제 늑대) ↔ Sniffing 도청 (혹은 가로채기)
      • 세션 하이재킹 공격(Session Hijacking)
      • SSL 스트리핑(SSL Stripping) 등

HTTPS 보안 적용 방식

HTTPS 는 대칭키 암호화 방식과 비대칭키 암호화 방식의 장점만을 사용

  • 비대칭키 암호화 장점 : 공개키는 누구나 볼 수 있고 노출되어도 안전하나 연산 속도가 느림
    • 노출되어도 안전한 공개키를 클라이언트에게 공유하여 암호화 통신을 위한 시작을 엶
      • 비대칭 암호화는 갑을 관계를 내포한다 갑(비공개키)과 을(공개키)
        • 1 : N = 단일 서버 : 다수 클라이언트
          • 1 = 단일 서버만 사용 가능한 키 : 비공개키
          • N = 다수 클라이언트라면 모두 사용 가능한 키 : 공개키
  • 대칭키 암호화 장점 : 키가 노출되면 매우 위험하지만 암호화/복호화 연산 속도가 빠름
    • 연산속도가 빨라 매번 클라이언트와 서버가 요청/응답을 주고받을때 성능에 영향을 안끼침

HTTPS 는 암호화 방식 2개 모두 사용 : 비대칭키(Public, Private), 대칭키(’세션키’로 부름)

  • 서버와 클라이언트가 비대칭키를 주고받아, 그걸 통해 생성한 대칭키(’세션키’로 부름)로 암호화 통신
    • 상세한 방식은 좀 있다가 아래에서 설명할 예정
  • 서버는 클라이언트에게 비대칭키 중 공개키(Public)를 그냥 전달하지 않고 CA 인증기관의 인증 후 전달
    • CA : SSL 인증서를 발급하는 기관, 신뢰할 수 있는 기관 진품 인증서
      • 인증 기관에 의해 인증된 서버인지 = 인증 기관에 의해 암호화된 ‘서버의 공개키’ 인지
      • 피싱 방지 : 클라이언트가 실제로 도메인을 소유하고 있는 올바른 서버와 통신하고 있는지 확인 목적
        • 해당 웹 서버의 주소, 소유주, 이메일 주소, 회사 및 개인 정보 등을 CA 가 전자문서화(인증)

HTTPS 동작 원리

  • 2개의 비대칭키 Pair : 갑을 관계
    1. 서버의 공개키 + 서버의 비공개키 : HTTPS 적용하려는 웹 서버가 갑 + HTTPS 통신할 클라이언트가 을
      • 서버의 공개키는 아래 CA의 비공개키로 암호화하여 클라이언트에게 전달할 예정
    2. CA의 공개키 + CA의 비공개키 : 인증을 해주는 주체인 CA 가 갑 + 인증 받아야하는 많은 웹 서버가 을
  • 1개의 대칭키 : 가장 마지막에 서버와 클라이언트가 주고받기 위해 사용하는 암호/복호화 성능이 좋은(빠른)키
    1. 세션키 : 아래의 그림에서 가장 마지막 단계 (C)
      • 정확히는 클라이언트가 서버의 공개키를 통해 서버의 비공개키를 가진 서버와 통신하는것이 아니고
      • 최종적으론 이 서버의 비대칭키 Pair 를 통해 ‘클라이언트와 서버’ 서로만 알 수 있는 대칭키로 통신

  • (A) 비대칭키 (서버 공개키 / 비공개키) + (B) 비대칭키 (CA 공개키 / 비공개키) + (C) 대칭키 (= 세션키)

웹 보안 : CORS = CSRF(유저 비의도적 요청) 부분 방지를 위한 웹 브라우저 정책

웹 보안 : HTTPS 와 웹 브라우저에서의 CORS

  • HTTPS 는 웹 통신 내 요청, 응답에 대한 암호화
  • CORS 는 웹 브라우저에서 악의적 웹 요청(CSRF)에 대한 ‘부분적’ 방어 정책
    • ‘부분적’의 의미 : 완벽하게 CORS 를 방어하지 못한다는 의미

웹 브라우저의 보안 정책인 SOP 그 후의 CORS

웹 브라우저는 자바스크립트를 동작시키는 엔진을 갖고있어, 무궁무진한 작업 수행이 가능함과 동시에

해커가 자바스크립트를 통해 위험한 작업을 수행할 수 있는 무한한 가능성 보유

→ 유저가 웹 브라우저를 정상적으로 사용할때, 악의적인 자바스크립트 수행으로 타 서버를 공격 가능

  1. W3C 는 가장 먼저 SOP 라는 정책 표준을 도입하여 웹 브라우저에서의 방어를 하도록 했는데
  2. API 호출이 사실상 필수인 프론트엔드 개발자들로부터 온갖 욕을 먹고 추가 정책인 CORS 를 도입
    • 프론트엔드 개발자들이 자바스크립트를 통해 특정 조건하에서는 자유로운 API 호출 가능

CSRF (Cross-Site Request Forgery)

CSRF : 타 사이트에 대한 의도치 않은 요청

A 사이트를 이용하는 유저를 통해 타 B 사이트(크로스사이트)에 의도치 않은 요청이 보내지는 것

  • 꼭, 웹 브라우저에서만 가능한것뿐만 아니라 네이티브 앱에서도 가능
    • 웹 브라우저에서 CSRF 형태 : 유저가 의도하지 않은 요청이 자바스크립트 실행을 통해 서버에 전송
      • 서버에 요청을 보내는 자바스크립트 = AJAX (Asynchronous JavaScript and XML)

CS__ (Cross-Site) 와 CO__ (Cross-Origin) : Same-Site, Same-Origin 차이

  • Origin 과 Site 의 차이

    • Origin : Scheme + Host Name (Domain Name) + Port

      • ex ) https://www.naver.com:8080
    • Site : Domain Name 중 SLD (Second-Level Domain) + TLD (Top-Level Domain)

      • ex ) api.naver.com / admin.naver.com (api 혹은 admin 은 Sub Domain)

      • 다른 말로 정의하자면 TLD + 1 혹은 eTLD + 1 영역

        • TLD (Top-Level Domain) 에는 eTLD (유효 TLD) 개념이 존재

          • api.aaron.com : .comTLD | .aaron.comTLD + 1
          • api.aaron.co.kr : .co.kreTLD | .aaron.co.kreTLD + 1

  • Domain, Origin 과 Site 의 차이 정리
    • Domain : www.naver.com
    • Origin : https:// + www.naver.com + :8080
    • Host : www.naver.com + :8080
    • Site : naver.com

CORS (Cross Origin Resource Sharing)

CORS : AJAX 통한 타 사이트 웹 서버에 대한 (의도치 않은) 요청 방어를 위한 웹 브라우저의 정책

1. 웹 브라우저 에서 2. 자바스크립트 AJAX 를 통한 CSRF (크로스사이트에 대한 악의적 요청) 방지

  • 1. 웹 브라우저 : 네이티브 앱에서는 CSRF 방어하기 위해 XSRF Token 사용 (임의 난수 + 세션 활용)
  • 2. 자바스크립트 AJAX : 웹 브라우저에서 AJAX 가 아닌 FORM 을 통한 POST 요청 방어 불가

→ CORS 를 통해 모든 CSRF 공격을 방지할 수 있는건 아니라는 것

  • CORS 는 웹 브라우저에서만의 정책
    • 네이티브 어플리케이션의 경우 CORS 가 적용되지 않기에 방어 불가 → XSRF 토큰 필요
  • CORS 는 AJAX에 대한 정책
    • AJAX 가 아닌 FORM 을 통한 POST 요청에는 CORS 정책이 적용되지 않아 여전히 XSRF 이슈

웹 브라우저 비동기 지원 AJAX

  • FORM (Synchronous) = 보내고 끝 (HTML 페이지 반환 = 페이지 리렌더 O)
  • AJAX (Asynchronous JavaScript and XML) = XHR (XML 객체 반환 = 페이지 리렌더 X)
    • 비동기 = XHR 객체 활용 시 서버에 데이터 요청, 수신 가능
      • 즉, 웹 페이지 전체를 다시 로딩하지 않고 일부분만을 갱신할 수 있게 된다.
      • XHR (XmlHttpRequest) : W3C 표준이 아님 (브라우저마다 설계 방식 차이)
        • 화면이 없는 내장 브라우저로 HTML 문서를 받을 필요가 없고, 데이터를 XML 로 송수신
        • 통신 시 필요한 데이터를 XML (현대엔 JSON) 형식으로 주고 받는 역할로 AJAX 가능
        • 현재 대부분의 주요 웹 브라우저는 서버에 데이터를 요청하기(API) 위해 XHR 객체 활용

웹 브라우저 보안 정책 SOP (Same-Origin Policy)

웹 브라우저에서 HTTP Resource 를 갖고오기 위한 모든 HTTP 요청은 기본적으로 SOP

  • 웹 브라우저는 SOP (Same Origin Policy) 정책

웹 브라우저는 이미지, 아이콘처럼 외부에서 정보를 가져오는 경우가 있기 때문에

  • SOP (Same-Origin Policy) 정책은 ‘Same-Origin’ 이름과 달리 부분적으로 Cross-Origin 를 허용
    • Cross-Origin ’가져오기’ (<img/>, <script/>) : 의도된 조회 = 서버 상태 변경 불가
    • Cross-Origin ’제출하기’ (FORM) : 개발자가 설계한 의도된 제출 = 의도된 서버 상태 변경
  • Cross-Origin ’요청하기’ (AJAX - 예, POST) : 서버 상태 변경 가능 → 이건 SOP 에서도 불허
    • Cross-Origin 에 대한 AJAX 는 Cross-Origin 서버 상태를 바꿀 수 있는 보안 위험성 존재
      • POST, DELETE 와 같은 AJAX 호출은 Cross-Origin 서버 상태 변경 가능

SOP 보완 정책 = CORS (Cross Origin Resource Sharing)

그렇다고 API 호출의 사실상 표준인 AJAX 를 막으면 프론트엔드 개발이 아예 불가능

→ 결국 AJAX 에 대한 예외적 허용을 위한 SOP 를 보완하는 추가 보안 정책이 필요 : CORS

  • AJAX 는 CORS 정책에 맞을시에만 조건부 허용
  • 웹 브라우저에서 처리하는것 이기에 서버-서버 통신시에는 CORS 이슈 미발생
  • React - Spring 일땐 CORS 가 발생했었으나 React 에 Proxy 설정 혹은 Next.js 도입 뒤 CORS 미발생

CORS 서버 측 적용 방법 : Header

웹 서버는 웹 브라우저로부터 어떤 요청만 허용하는지 3가지 CORS 헤더 설정으로 호출가능 요청을 제약

  1. 허용된 Origin *(예, a.com)*
    • Origin (브라우저) → 1. 브라우저가 요청할 때 전송
    • Access-Control-Allow-Origin (서버) → 2. 서버가 응답할 때 전송
      1. 브라우저는 1. 브라우저가 요청할때 보낸 헤더2. 서버가 응답할때 보낸 헤더를 비교해 유효성 검사
      • 아래부터 1. → 2. → 3. 으로 나누어서 어떻게 적용되는지에 대한 순서
  2. 허용된 Method *(예, GET, HEAD 만 허용하고 POST, DELETE 등은 제외)*
    • Access-Control-Request-Method (브라우저) → 1.
    • Access-Control-Allow-Method (서버) → 2.
      1. 브라우저가 1. 과 2. 을 비교하여 요청의 유효성 검증
  3. 허용된 Header
    • Access-Control-Request-Headers (브라우저) → 1.
    • Access-Control-Allow-Headers (서버) → 2.
      1. 브라우저가 1. 과 2. 을 비교하여 요청의 유효성 검증
  • 웹 브라우저가 요청 시 자격증명 Header 전달 허용
    • 자격증명 : Cookie, Authorization Headers 또는 TLS Client 인증을 위한 정보들
    • 자격증명(인증) 요청 시 allowCredentials = true 혹은 credentials: “include” (브라우저) → 1.
      • 요청에 자격증명(인증)과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션
        • credentials: “include” : 최신 자바스크립트 fetch() 활용한 API 호출
        • allowCredentials = true : 구식 자바스크립트 XMLHttpRequest 활용한 API 호출
    • Access-Control-Allow-Credentials = true (서버) → 2.
      • 웹 서버(예, Spring Boot)측에서 본 헤더 설정을 통해 자격증명이 담긴 요청을 받을 수 있게 된다.
      • Access-Control-Allow-Credentials 사용시 Access-Controll-Allow-Origin 헤더 제약 존재
        • Spring Security 에서 Access-Controll-Allow-Origin 이 * 이면 안되는 강력한 제약사항
        • 심화 질문 : 왜 Spring Security 에서 allowedOrigins(*) 를 금지할까?
          • 대신 allowOriginPatterns(*) 를 사용하도록 Spring Security 는 제안한다.
      1. 브라우저가 1. 과 2. 을 비교하여 요청의 유효성 검증

→ 브라우저는 서버에서 설정한 위 3가지 CORS 설정을 서버 호출로 파악

CORS 검증을 위한 요청

1. Simple Request : 서버 상태 조회

  • 서버 상태 조회를 위한 Methods :
    • GET, HEAD, POST (몇몇 간단한 Header 에 대해서만)
  • 허용된 Origin 체크 절차
    • 브라우저가 서버에게 원 요청 을 보내면
    • 서버는 “결과”와 함께 “CORS 헤더”를 같이 전송
    • 브라우저는 “CORS 헤더” 가 요청과 부합하지 않으면 ⇒ 반환 결과 폐기

2. Preflight Request : 서버 상태 변경

  • 서버 상태 변경를 위한 Methods :
    • GET, HEAD, POST (그 외 모든 종류의 커스텀 Header)
    • DELETE, PATCH, PUT
  • 허용된 Origin 체크 + 허용된 Method 체크 + 허용된 Header 체크 절차
    - 브라우저가 서버에게 임시 요청(Preflight, OPTIONS) 을 보내면
    - 서버는 “CORS 헤더”만 전송
    - 브라우저는 “CORS 헤더” 가 요청과 부합하지 않으면 ⇒ 원 요청 미전송
profile
(와.. 정말 Chill하다..)

0개의 댓글