웹 브라우저 내 저장 : 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) 로그인 계정 정보
Stateful HTTP : Cookie 와 Session 의 필요성 → 요청 식별
서버는 웹 브라우저의 요청이 어떤 유저에 의해 요청된 것인지 알기위해 응답 반환시 요청자 정보를 함께 반환
- 웹 브라우저는 응답을 받아, 응답 헤더에 붙어있던 요청자 정보를 웹 브라우저 쿠키에 저장
- 웹 브라우저는 이후 요청부터 웹 서버에게 요청자 정보를 함께 전달하여 웹 서버는 누구의 요청인지 식별 가능
- 요청자 정보 : 어떤 웹 브라우저가 요청했는지 인지 가능한 정보
- 로그인한 계정 정보
저장 장소로 구별되는 Cookie & Session
이 요청자 정보 를 어디에 저장하는지에 따라 다른 방법론 : Cookie 혹은 Session
- 웹 브라우저에 저장 : Cookie (클라이언트 측)
- 쿠키는 어떤 값이든 가능하나, 일반적으로 노출 방지를 위해 인간이 이해할 수 있는 형태가 아닌걸로
- 웹 서버에 저장 : Session (서버 측, 쿠키를 안쓰는게 아니라 웹 브라우저 쿠키에 SESSION_ID 를 저장)
- 웹 브라우저에 저장할 수 없을 정도로 크거나 복합적인 정보인 경우
- 웹 브라우저에 저장할 수 없는 민감 정보인 경우 → 즉, 로그인 정보 혹은 기타 정보를 서버에 저장하는 것
브라우저 내 Cookie 생성 방법

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

- 웹 브라우저가 그 이후로 웹 서버에게 전달할 때 : 웹 브라우저 요청(Request)의 헤더 Cookie 로 전송
Cookie 사용 이유 및 과정
Cookie = 웹 서버의 제어 + 웹 브라우저 내 저장 및 전송
웹 서버의 제어 = Set-Cookie 헤더를 통해 어떤 데이터를 쿠키로 쓸 것인지, 유효시간 및 보안 설정
Cookie 사용 기준 : Domain + Path
- 웹 브라우저가 쿠키를 웹 서버에게 전송하는 기준 (전송할지, 말지) = 해당 쿠키를 어떤 요청에 보낼지
- 모든 쿠키에는 도메인이 연결됨
- 예) 웹 브라우저 내 저장되어있는 쿠키 리스트
- 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 는 창을 닫았다가, 다시 키면 사라져있음
두 종류의 Cookie 차이 → 쿠키 유효시간 : MaxAge / Expires
Cookie 보안 (HttpOnly, Secure, SameSite)
Cookie에서의 보안의 중요성
: 유저 로그인 인증을 위한 정보 저장이나 웹앱에서 광고 및 마케팅 목적을 위한 식별자로 사용되는 기술로
웹 브라우저에 저장되어 있어서 쿠키 조회가 가능하고, 웹 브라우저가 웹 서버에 요청 시 탈취도 가능
-
HttpOnly : XSS(자바스크립트) 공격에 의한 쿠키 접근 제어
-
Secure : 패킷 탈취(Man-in-the-Middle) 방지를 위해 HTTPS 채널에서만 사용
MITM 방지 : 요청(클라이언트)-응답(서버) 사이에서 요청, 응답 탈취
-
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

Chrome Cookie SameSite 전략 기본값 Lax 로 변경 → 영향
-
None
도메인 검증 과정이 없어 모든 도메인에서(서드파티 쿠키에서도) 쿠키를 전송하고 사용 가능
사용자가 사이트 간 요청 위조(CSRF - Cross-site request forgery) 및
의도하지 않은 정보 유출에 취약 → Secure 옵션 설정 (https만 접근 가능) 필요
-
Lax
자사 도메인이 아니더라도(서드파티 쿠키여도) 일부 케이스에서는 접근 허용
→ 상태를 변경하지 않는 Get 요청만 허용
-
Strict
자사 도메인에서의(퍼스트파티 쿠키의) 전송만 허용
변경 사유가 뭘까?
- 보안 및 개인정보 보호 문제
- 쿠키가 많아지면 Request에 오버헤드 발생
우리가 할 일
- cross-site에서 쿠키를 사용할 수 있어야 하는 경우 (광고, 쿠키) → 쿠키 생성 시 samesite=none, secure 옵션 부여
- 쿠키 생성 시 samesite=none만 있으면 secure 옵션도 부여
- http 페이지에서 쿠키를 담아 https를 호출해야 하는 경우 → 호출 페이지를 https로 변경
서드파티 Cookie 정의와 실제 사례
Cookie Domain ≠ Site Domain
많은 홈페이지들을 오가며 유저의 행동을 기록, 추적하기 위한 Google Ads 정보 수집
- 실제 현업에서의 퍼스트파티 쿠키와 서드파티 쿠키의 예시

웹 브라우저 내 저장 : 2) Storage = 저장소
Storage 는 Cookie, Session 처럼 Stateful HTTP 를 위한 기술은 아님
Storage (HTML5 표준) 등장 전에는 웹 브라우저 저장소는 유일하게 Cookie 만을 활용
Storage (HTML5 표준) 등장 후에는 웹 브라우저에서 아래 두 유즈케이스를 제대로 나눠 활용
웹 브라우저 내 저장소 Storage 와 Cookie 목적 차이
- Storage : 웹 브라우저 저장소
- 유저에 의해 변경된 옵션 상태 등 → 필요에 따른 조회가 필요할때 (진짜 저장소)
- 예) 마지막에 어떤 소셜 계정으로 로그인했는지 저장하고, 1년 뒤 로그인할때 표시하여 알려줌
- Cookie : 웹 서버에게 웹 브라우저가 매번 전달할 특정 정보를 위한 저장소 (Stateful)
- 로그인 인증 정보 등 → 웹 서버가 요청마다 필요한 정보를 웹 브라우저에 넣어두고 전달받아 씀
- 생각해보기 : Storage 에 저장할까? Cookie 에 저장할까?
- 사용자가 방문한 페이지를 저장 : Storage
- 검색기록 : Storage
- 장바구니 : Storage
- 로그인 정보 저장 / 로그인 상태 유지 : Cookie
- 유저에 의해 변경된 옵션의 상태 : Storage
브라우저에 저장된다는 점에선 Storage 와 Cookie 는 동일하지만,
- Cookie : 웹 서버에게 반복적으로 전달하기 위한 + 작은 정보 + (만료 시간을 갖고)
- Storage : 웹 브라우저에서만 사용가능한 + 큰 정보 + (만료 시간 없이)
Storage 의 종류 : Storage 유효 시간에 따라
- Local Storage : 웹 브라우저 창이 닫혀도 영구적으로 저장 - 용량 처리 조심
- Session Storage : 웹 브라우저 창이 닫히면 삭제
Storage 의 종류별 용례
- 프론트엔드 개발자가 브라우저에서 무엇인가를 저장한다하면, Storage 를 쓸 것
- 단발적인 내용은 Session Storage, 길게 저장해도되는 내용은 Local Storage
- 예) 최근에 로그인했던 수단을 표기하기 위해 Local Storage 내 수단 저장
웹 브라우저 내 저장소 Cookie 와 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 다수 사용
- 메모리 중심 인스턴스의 비용 이슈 (비싼 메모리), 확장성 이슈 (비싼 인스턴스)
Cookie 의 단점 → Session 의 장점
- 쿠키 정보가 웹 브라우저에 저장되다보니
- 민감 정보들이 안전하지 않은 채로 저장되어있고 (HttpOnly, Secure, SameSite 방어는 가능)
- 웹 브라우저간 공유 불가 : 웹 브라우저 단위의 저장소이다보니 지역성 문제
- 각각의 웹 브라우저에서 한 행동들이 각각의 웹 브라우저에만 기록
- Session 은 정보를 웹 서버측에 저장
- 민감 정보들이 웹 서버측에 안정적으로 저장
- 웹 브라우저간 공유 가능 : 여러 웹 브라우저를 돌아다니며 행동해도 모두 서버에 중앙 기록
- 쿠키는 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 : 갑을 관계
- 서버의 공개키 + 서버의 비공개키 : HTTPS 적용하려는 웹 서버가 갑 + HTTPS 통신할 클라이언트가 을
- 서버의 공개키는 아래 CA의 비공개키로 암호화하여 클라이언트에게 전달할 예정
- CA의 공개키 + CA의 비공개키 : 인증을 해주는 주체인 CA 가 갑 + 인증 받아야하는 많은 웹 서버가 을
- 1개의 대칭키 : 가장 마지막에 서버와 클라이언트가 주고받기 위해 사용하는 암호/복호화 성능이 좋은(빠른)키
- 세션키 : 아래의 그림에서 가장 마지막 단계 (C)
- 정확히는 클라이언트가 서버의 공개키를 통해 서버의 비공개키를 가진 서버와 통신하는것이 아니고
- 최종적으론 이 서버의 비대칭키 Pair 를 통해 ‘클라이언트와 서버’ 서로만 알 수 있는 대칭키로 통신

- (A) 비대칭키 (서버 공개키 / 비공개키) + (B) 비대칭키 (CA 공개키 / 비공개키) + (C) 대칭키 (= 세션키)
웹 보안 : CORS = CSRF(유저 비의도적 요청) 부분 방지를 위한 웹 브라우저 정책

웹 보안 : HTTPS 와 웹 브라우저에서의 CORS
- HTTPS 는 웹 통신 내 요청, 응답에 대한 암호화
- CORS 는 웹 브라우저에서 악의적 웹 요청(CSRF)에 대한 ‘부분적’ 방어 정책
- ‘부분적’의 의미 : 완벽하게 CORS 를 방어하지 못한다는 의미
웹 브라우저의 보안 정책인 SOP 그 후의 CORS
웹 브라우저는 자바스크립트를 동작시키는 엔진을 갖고있어, 무궁무진한 작업 수행이 가능함과 동시에
해커가 자바스크립트를 통해 위험한 작업을 수행할 수 있는 무한한 가능성 보유
→ 유저가 웹 브라우저를 정상적으로 사용할때, 악의적인 자바스크립트 수행으로 타 서버를 공격 가능
- W3C 는 가장 먼저 SOP 라는 정책 표준을 도입하여 웹 브라우저에서의 방어를 하도록 했는데
- 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 차이
- 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 미발생
웹 서버는 웹 브라우저로부터 어떤 요청만 허용하는지 3가지 CORS 헤더 설정으로 호출가능 요청을 제약
- 허용된 Origin *(예, a.com)*
- Origin (브라우저) → 1. 브라우저가 요청할 때 전송
- Access-Control-Allow-Origin (서버) → 2. 서버가 응답할 때 전송
- 브라우저는 1. 브라우저가 요청할때 보낸 헤더와 2. 서버가 응답할때 보낸 헤더를 비교해 유효성 검사
- 아래부터 1. → 2. → 3. 으로 나누어서 어떻게 적용되는지에 대한 순서
- 허용된 Method *(예, GET, HEAD 만 허용하고 POST, DELETE 등은 제외)*
- Access-Control-Request-Method (브라우저) → 1.
- Access-Control-Allow-Method (서버) → 2.
- 브라우저가 1. 과 2. 을 비교하여 요청의 유효성 검증
- 허용된 Header
- Access-Control-Request-Headers (브라우저) → 1.
- Access-Control-Allow-Headers (서버) → 2.
- 브라우저가 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. 과 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 헤더” 가 요청과 부합하지 않으면 ⇒ 원 요청 미전송