노트

브라우저 요청과 서버 간 요청

Browser Requests vs. Server-to-Server Requests

프런트엔드#security#network · 연결된 개념 10개

쉽게 말하면

브라우저는 누구나 와서 아무 코드나 돌리는 PC방 컴퓨터라서, 사용자 로그인 정보를 지키는 규칙이 많아요. 서버는 허락받은 사람만 코드를 올리는 서버실이라 그런 제한 없이 요청을 보내요.

비유가 깨지는 곳 규칙이 없다는 건 안전하다는 뜻이 아니라 책임이 개발자에게 넘어온다는 뜻이에요. BFF는 받은 쿠키를 직접 헤더에 넣어 넘겨야 하고, 외부 입력으로 요청 주소를 정하면 SSRF가 돼요.

같은 HTTP 요청이라도 브라우저에서 보내면 여러 보안 규칙이 강제되고, 서버에서 보내면 아무 제한이 없다. 브라우저 보안 정책은 신뢰할 수 없는 코드로부터 사용자를 지키려고 있기 때문이다.

브라우저 → 서버서버 → 서버
실행되는 코드아무 웹사이트의 JS(JavaScript)개발자가 배포한 코드
SOP(Same-Origin Policy)·CORS(Cross-Origin Resource Sharing)적용없음
쿠키Domain·Path·SameSite 규칙대로 자동 첨부아무 쿠키나 헤더에 직접 넣음
HttpOnly 쿠키JS로 못 읽음요청에서 그냥 읽음
보안 책임브라우저가 강제개발자

브라우저는 PC방 컴퓨터와 같다. 누구나 와서 코드(웹사이트)를 실행하고, 사용자의 로그인 상태가 들어 있으니 규칙이 필요하다. 서버는 권한 있는 사람만 코드를 올리는 서버실이라 그런 규칙이 필요 없고, 있으면 외부 API 호출 자체가 불가능하다. curl이나 Postman에서 CORS 에러가 나지 않는 이유도 같다. 동일 출처 정책과 CORS는 오직 브라우저 안에서만 존재한다.

SSR(Server-Side Rendering)·BFF(Backend for Frontend)에서 쿠키 넘기기

Next.js 같은 서버가 브라우저와 백엔드 API 사이에 낀 구조(BFF)에서는 두 구간의 규칙이 다르다.

  1. 브라우저 → Next.js 서버: 브라우저 규칙 적용, 쿠키 자동 첨부
  2. Next.js 서버 → API: 서버 간 요청. 받은 쿠키를 직접 헤더에 넣어 전달해야 한다
  3. API가 Set-Cookie를 주면 Next.js가 브라우저로 다시 전달하고, 브라우저가 Domain 규칙대로 저장한다

이 구조에서는 내부 API 주소가 브라우저에 드러나지 않는다는 장점이 있다. 대신 보안을 개발자가 챙겨야 한다. 특히 외부 입력으로 요청 주소를 정하면 서버 측 요청 위조(Server-Side Request Forgery, SSRF)가 된다.

// 위험: 외부 입력으로 정한 주소에 모든 쿠키를 보냄 (SSRF + 쿠키 유출)
fetch(req.query.url, { headers: { cookie: allCookies } })
 
// 안전: 고정된 내부 주소에 필요한 쿠키만
fetch(process.env.INTERNAL_API_URL, { headers: { cookie: `sid=${sid}` } })

관련: HTTP 쿠키, 서버 함수, 서버 컴포넌트에서의 데이터 요청, 서버 간 호출 방식 → 스프링에서 외부 API 호출

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • CSRF

    CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조)는 로그인한 사용자가 악성 사이트를 방문했을 때, 그 사이트가 사용자의 브라우저를 시켜 사용자 모르게 원래 사이트에 요청을 보내게 하는 공격이다. 공격자는 토큰을 훔치지 않는다. 브라우저가 쿠키를 알아서 붙여 준다는 점을 이용한다.

  • XSS

    XSS(Cross-Site Scripting)는 공격자가 넣은 스크립트가 내 사이트의 출처(origin) 권한으로 사용자 브라우저에서 실행되는 공격이다. 같은 출처의 코드로 돌기 때문에 same-origin-policy가 막아 주지 못한다. 그 스크립트는 페이지를 바꾸고, 로그인한 사용자 행세를 하며 요청을 보내고, JS가 읽을 수 있는 데이터(localStorage의 토큰 등)를 빼 갈 수 있다.

  • 브라우저 캐시

    한 번 받은 리소스(HTML·CSS·JS·이미지)를 브라우저가 저장해 두었다가 다시 쓰는 기능. 서버가 응답 헤더로 얼마나, 어떻게 캐시할지 알려 주고 브라우저가 그대로 따른다.

  • Django의 CSRF 방어

    Django는 CsrfViewMiddleware로 CSRF(Cross-Site Request Forgery)를 막는다. 기본 아이디어는 Double Submit Cookie, 즉 쿠키에 든 CSRF 값과 요청에 함께 보낸 값을 비교하는 것이고, 여기에 토큰 마스킹(token masking)과 Origin·Referer 검사를 더한다.

  • localStorage와 sessionStorage

    브라우저에 문자열 키-값을 저장하는 Web Storage API의 두 가지. 쿠키와 달리 요청에 자동으로 실리지 않고, 출처 단위로 나뉘며(same-origin-policy), 보통 출처당 5MB 안팎을 쓸 수 있다. 동기 API라 큰 데이터를 자주 읽고 쓰면 메인 스레드를 막는다.

보기 옵션