HTTP
Hypertext Transfer Protocol: 웹 상에서 자원을 주고 받기 위한 프로토콜
- TCP 기반
- 클라이언트-서버 모델에서의 요청-응답 프로토콜로 작동
- 무상태(Stateless), 비연결성(Connectionless)
HTTP 요청(Request)
The request message consists of the following:
- a request line (e.g., GET /images/logo.png HTTP/1.1)
- request header fields (e.g., Accept-Language: en)
- an empty line
- an optional message body
요청 메소드(Request method, verb)
리소스에 어떤 행동을 원하는지 알림
GET
: 리소스의 표현(representation) 요청
HEAD
: 리소스의 GET
요청에 들어갈 응답 헤더들을 확인
POST
: URI로 표현된 리소스 생성
PUT
: 특정 URI에 원하는 entity 삽입 (이미 있으면 덮어씀)
DELETE
: 리소스 삭제
OPTIONS
: 해당 URL에서 서버가 지원하는 메소드들을 확인
PATCH
: 리소스의 부분적인 수정
PUT
과 DELETE
는 역등적(idempotent)인 메소드임
- 같은 요청을 여러 번 날려도 같은 효과를 냄
GET
과 HEAD
, OPTNIOS
등 서버의 상태를 바꾸지 않는 메소드들(Safe methods)도 역등적임
POST
는 역등적이지 않음 (요청 한 번마다 새 리소스가 생성되기 때문!)
HTTP 응답(Response)
The response message consists of the following:
- a status line which includes the status code and reason message (e.g., HTTP/1.1 200 OK, which indicates that the client's request succeeded)
- response header fields (e.g., Content-Type: text/html)
- an empty line
- an optional message body
상태 코드(Status code)
문제 발생 여부와 원인 진달을 위해 상태를 표시하는 값
1XX
: 정보
2XX
: 성공 (e.g. 200 OK
, 204 No Content
)
3XX
: 리다이렉션 (e.g. 301 Permanently Moved
, 302 Temporarily Moved
)
4XX
: 클라이언트 에러 (e.g. 400 Bad Request
, 404 Not Found
)
5XX
: 서버 에러 (e.g. 500 Internal Server Error
, 503 Service Unavilable
)
HTTP의 연결 유지
HTTP/1.0까지는 한 번의 요청-응답만 하고 연결을 끊었음
HTTP pipelining
HTTP/1.1부터 추가된 기능, 한 번의 TCP 연결에 여러 개의 요청을 전송함
- 클라이언트가 각 요청에 대한 응답을 기다리지 않고, 여러 개의 요청을 연속적으로 보냄
- 서버는 요청 순서대로 응답을 전송해야 함
- 이는 FIFO 방식이므로, 거대한 요청(e.g. 크기가 큰 파일) 하나 때문에 다른 요청들이 지연될 수 있음
- HOL blocking(Head-of-line blocking) 문제
- 따라서 브라우저는 보통 이 방식을 사용하지 않고, 여러 개의 연결을 맺어 요청을 보냄
Persistent connection (keep-alive)
HTTP/1.1부터 추가된 기능, 연결을 끊지 않고 재활용할 수 있음
Connection
헤더와 Keep-Alive
헤더를 사용
- TCP의 3-way handshaking으로 인한 레이턴시를 줄임
- TCP의 Slow start에 의해 연결이 더 빨라짐
HTTP session state
웹 애플리케이션에서 HTTP 요청에 상태를 부여하기 위해 사용하는 개념
서버 사이드 세션(Server-side web session)
서버에서 클라이언트마다의 세션을 관리
- 클라이언트마다 고유한 세션 ID를 발급함
- 클라이언트에서는 세션 쿠키에 자신의 세션 ID를 저장하고, 통신 시마다 헤더로 세션 ID 값을 보임
HTTP 쿠키(HTTP Cookie)
브라우저에 저장되는 쿠키로 원하는 데이터 저장
- 서버의
Set-Cookie
응답 헤더를 통해 브라우저에 쿠키를 생성함 (서버에서 쿠키 생성을 강제할 수 있음)
- 서버로 요청을 보낼 때 해당 도메인의 모든 쿠키를
Cookie
헤더에 담아 전송함
- 로그인 유지 등에 사용
- Session cookie: 서버의 세션 ID를 기억하기 위한 쿠키
- Persistent cookie: 세션 쿠키와 다르게, 특정한 기한동안 저장되는 쿠키
- Http-only cookie: 클라이언트의 스크립트로 읽을 수 없고, 서버로 전송할 때에만 활용되는 쿠키 (HttpOnly 플래그 설정)
- XSS 공격을 막기 위해 사용됨
- CSRF 공격을 막을 수는 없음
- Third-party cookie: 방문하는 페이지와 도메인이 다른 쿠키
- 페이지 내 광고 배너 등을 통해서 심어지며, 광고 서비스에서 사용자의 방문 기록 추적으로 맞춤형 광고를 제공하기 위해 사용됨
- Safari와 Firefox는 2020년 서드파티 쿠키를 기본적으로 차단하도록 했고, Chrome 또한 2022년에 이를 시행하기로 계획했음
Web Storage API
브라우저에서 특정 도메인을 위한 데이터들을 보관하는 저장소
- 각각 출처에 대해 독립적인 저장 공간을 제공함
- 쿠키와 달리, 서버로 데이터를 전송하지 않음
- sessionStorage: 페이지 세션이 유지되는 동안 제공
- 브라우저 탭이 닫히면 사라짐
- JS의
Window.sessionStorage
속성을 통해 사용
- localStorage
- 유효기간 없이 데이터를 저장함
- JS의
Window.localStorage
속성을 통해 사용
HTTPS
HTTP에 보안 기능(TLS)이 추가된 프로토콜
- 패킷 도청(Eavesdropping)으로부터 보호함
- Wi-Fi 등 안전하지 않은 네트워크에서 다른 사람이 패킷을 훔쳐볼 수 있음 (packet-sniff)
- 중간자 공격(Man-in-the-middle attack)으로부터 보호함
- 통신을 제 3의 인물이 중계한다면, 중간에 데이터를 위/변조하여 서로 잘못된 정보를 전달하게 할 수 있음 (통역사가 타락하면 위험!)
TLS(SSL)
Transport Layer Security: 전송 계층의 통신에 보안 기능을 추가하기 위한 기능
- 핸드셰이킹을 통해 양쪽에 대칭 키를 생성하고, 전송하는 데이터를 대칭 키로 암호화함
인증서(Digital certificate, Public key certificate)
공개 키의 소유권을 인증하는 전자 문서
- 소유자의 정보와 발행자의 디지털 서명을 포함하고 있음
- 일반적으로 CA가 발행함
CA(Certificate authority)
인증서의 신뢰성을 보장하기 위한 기업
- 인증서를 발행하는 기관이므로, CA를 신뢰할 수 있어야 인증서를 신뢰할 수 있음
TLS handshake
- 클라이언트가 서버로 연결을 시작하는 메시지를 보내며, 이때 지원 가능한 TLS 버전과 암호화 방식들을 포함함
- 서버가 그 중 원하는 방식을 택하고, 클라이언트에게 자신의 결정을 알림
- 서버가 인증서(Certificate)를 보냄
- 클라이언트가 인증서의 유효성을 확인함
- 클라이언트와 서버가 같은 대칭 키(세션 키)를 생성하고, 이를 앞으로의 통신에 사용함
인증서의 유효성 확인 방식
- 인증서를 발급한 CA를 신뢰할 수 있어야 함
- 인증서가 해당 서버를 위한 인증서여야 함
세션 키 생성 방식 (무작위 수를 이용하는 방법)
- 클라이언트가 서버의 공개 키로 무작위 수를 암호화하고 서버로 보냄 (공개 키는 인증서에 들어있음)
- 서버가 자신의 비밀 키로 무작위 수를 복호화함
- 클라이언트와 서버 각자 해당 무작위 수로 대칭 키(세션 키)를 생성함
HTTP/2
HTTP/1.1보다 빠른 속도를 목표로 하여 개발된 프로토콜
- 클라이언트와 서버 간에 어떤 버전의 HTTP를 사용할 것인지 협의하도록 함
- HTTP/1.1과 높은 호환성을 가짐
- 여러 방법으로 레이턴시를 줄여서 웹 브라우저의 페이지 로드 속도를 높임
중복된 헤더는 테이블 내 인덱스 값만 전송하고, 중복되지 않은 헤더는 Huffman 인코딩을 거쳐 전송함
- 기존에는 쿠키를 전송하느라 헤더에 중복되는 평문을 반복적으로 전송해야 했으며, 쿠키의 크기가 KB단위만큼 커지기도 하면서 큰 오버헤드가 발생했음
- 클라이언트와 서버가 각자 같은 내용의 헤더 테이블을 갖고, 중복된 헤더를 주고받을 때 인덱스 값만 전송하도록 함
요청 다중화(Multiplexing of requests)
하나의 TCP 연결에서 여러 개의 요청과 응답을 주고받음
- 기존에는 한 번의 요청과 응답을 위해 하나의 TCP 연결을 사용했음
- HTTP/1.1의 pipelining 방식은 HOL Blocking 문제가 발생했음
- 따라서 HTTP/1.1의 keep-alive 방식으로 연결을 재활용했음
- 이때 브라우저가 가질 수 있는 연결의 수에 제한이 있었음
- 따라서 무거운 파일을 받을 때, 새로운 연결을 만들지 못 하고 기다려야 하는 HOL Blocking 문제가 발생했음
- HTTP 메시지를
Frame
이라는 단위로 쪼개어 보내고, 받은 쪽에서는 다시 조립함
Frame
: HTTP 메시지(요청 또는 응답)를 쪼갠 것
- 하나의
Stream
에서 여러 메시지들의 Frame
들을 주고받음
Stream
: 연결 내에서 Frame
을 주고받는 양방향 흐름
- 요청에 대한 응답을 받는 순서를 신경쓰지 않음
- 따라서 HOL Blocking 문제를 방지함
- 그러나, 패킷 유실 시 TCP의 순서 보장 기능에 의해 여전히 HOL Blocking이 발생할 수 있음 (이는 HTTP/3에서 해결됨)
서버 푸시(Server Push)
클라이언트가 요청하기도 전에 서버가 리소스를 보냄
- 기존에는 html 페이지를 읽으면서 필요한 리소스(css, js)를 그때그때 서버에 요청하는 방식으로, 부가적인 요청을 보내고 받는 오버헤드가 존재했음
- 서버 푸시 방식을 통해, 클라이언트가 요청할 리소스를 서버가 미리 한 번에 보냄
SOAP
Simple Object Access Protocol: HTTP로 정보를 주고 받는 프로토콜
- XML 메시지 형식으로 통신함
- 상태를 갖는 애플리케이션에 적합함
REST
Representational state transfer: HTTP 통신을 사용하는 표현적인 아키텍처 패턴
- REST 가이드라인을 따르는 웹 서비스를 RESTful하다고 부름
- 웹 리소스를 텍스트(URL)로 표현하고, 무상태(Stateless) 프로토콜로 읽거나 수정할 수 있도록 함
- 페이로드(payload)로 HTML이나 XML, JSON 등을 담음
- 아키텍처 패턴의 일종이기 때문에 공식적인 기준은 없음
- 하지만 많은 개발자들이 REST 제약조건을 모두 지키지 않은 체 RESTful API를 개발했다고 말함 (특히 Uniform interface 부분)
장점
- 확장성(scalability): 서버가 상태를 갖지 않으므로 확장에 용이함
- Uniform interface의 간단함(simplicity): 다양한 플랫폼에서 사용하기 쉬움
- 통신의 가시성(visiblity): 디버깅을 위해 HTTP 메시지를 확인할 수 있음
- 신뢰성(reliability): 시스템 실패에도 대응할 수 있음
제약조건
- 클라이언트-서버 구조
- 사용자 인터페이스에서의 이식성을 높임
- 서버의 확장성을 높임
- 무상태(Stateless)
- 애플리케이션의 상태를 클라이언트가 저장하도록 함
- 캐시 가능(Cachability)
- 리소스의 캐시 가능 여부를 알려줘야 함
- 캐싱을 통해 성능을 높임
- 계층화(Layered system)
- 클라이언트와 서버 사이에 프록시나 로드밸런서가 존재할 수 있음
- 시스템의 확장성을 높임
- 보안 기능을 중앙화할 수 있음
- 일관된 인터페이스(Uniform interface)
- 클라이언트와 서버 간에 느슨한 관계를 만듬
- 각자 독립적으로 발전할 수 있음
- Resource identification: URI로 리소스 식별
- 리소스 자체와 표현을 분리함 (같은 리소스를 여러 형식으로 전달 가능)
- 표현을 통한 리소스 수정: 리소스의 메타데이터 내 정보로 리소스를 수정하거나 삭제할 수 있음
- Self-descriptive messages: 메시지를 보면 어떤 작업을 수행할 지 직관적으로 알 수 있음
- e.g.
Content-Type
헤더로 리소스의 표현을 알림
- HATEOAS: Hypermedia as the engine of application state
- 홈페이지 역할의 최초 URI에서 시작하여, 하이퍼링크를 통해 리소스의 위치를 참조하도록 함
- 클라이언트에 리소스 위치를 하드코딩하지 않도록 함
GraphQL
API에서 데이터 쿼리와 수정을 위해 사용할 수 있는 언어
- 클라이언트가 데이터를 원하는 구조대로 응답받을 수 있음
- REST와 대조적으로 더 유연하지만 구현이 까다로움
WebSocket
TCP 연결을 통해 이중 통신(full-duplex)이 가능한 7계층 통신 프로토콜
- 상태를 가짐 (Stateful)
- HTTP 통신에 비해 낮은 오버헤드로 상호작용함
- HTTP/HTTPS와 같은 포트(80, 443)를 사용함
SOP
Same-origin policy: 동일 출처 정책
- 출처(Origin)가 같은 페이지 간의 데이터 공유만을 허용하는 브라우저의 보안 기능
- 의도치 않은 요청을 차단함
- 예시로, 브라우저에서 웹 사이트 A와 B를 다른 텝으로 열었을 때, B의 AJAX 요청을 통해 A의 서버로 악의적인 요청을 보낼 수 있음
- A의 인증 방식이 세션 쿠키 기반이라면, 브라우저는 AJAX 요청에 세션 쿠키 값을 넣을 것이며, B가 만든 악의적인 요청이 A의 서버로 전달될 것임
- 문제점: 클라이언트와 서버를 분리하면 도메인이 서로 달라질 수 있음
CORS
Cross-origin resource sharing: 출처 간 리소스 공유 정책
- SOP를 완화한 정책
- 요청에 허용된 도메인과 메소드, 헤더만 사용될 수 있도록 함
- 브라우저는 요청을 보내는 웹 사이트의 도메인과 요청 헤더, 메소드 등이 허용되는지 서버에 질의해야 함
작동 방식
- 단순히 원하는 요청을 보내보거나,
OPTIONS
메소드로 미리 사전 요청(Preflight)을 보냄으로써 허용되는 조건들을 응답받음
- 요청의
Origin
, Accss-Control-Request-*
헤더: 요청을 보낼 페이지의 도메인이나 메소드, 헤더 등
- 응답의
Acess-Control-Allow-*
헤더: 허용되는 도메인이나 메소드, 헤더 등
CSRF
Cross-site request forgery: 사이트 간 요청 변조
- HTTP 쿠키를 악용하여, 의도치 않은 맥락에 사용자의 의지와 무관한 요청을 전송하는 공격
- 예시로, 하이퍼링크로 특정 사이트의 비밀번호 변경 기능 API URL을 가리키면, 사용자가 링크를 클릭했을 때 사용자의 의지와 무관하게 비밀번호가 바뀔 수 있음
- 인증 방식이 쿠키 기반이면 CSRF 문제가 발생할 수 있음
- 요청 시 브라우저가 자동으로 헤더에 해당 도메인의 토큰 값들을 넣기 때문
XSS
Corss-site scripting: 사이트 간 스크립팅
- 다른 사용자가 보는 웹 페이지에 클라이언트 스크립트 코드를 주입하하여 악의적인 행동을 수행하는 공격
- 방지 방법:
- 서버에서 스크립트를 필터링함
- 중요한 쿠키에 HttpOnly 플래그를 설정하여 스크립트로 읽을 수 없도록 함
- 브라우저에서 선택적으로 스크립트를 비활성화함 (Content-Security-Policy, 콘텐츠 보안 정책)
Web server
웹 상에서 클라이언트의 HTTP 요청에 응답해주는 소프트웨어
- 웹 컨텐츠를 제공하기 위한 목적
- 일반적으로 정적 컨텐츠를 제공하고, WAS로 요청을 전달하여 동적 컨텐츠를 제공함
- 웹 서버가 정적 컨텐츠 제공에 최적화돼있기 때문
- 예시: Apache, nginx, Node.js
WAS(Web application server)
웹 애플리케이션을 제공하는 서버
- 웹 애플리케이션: 동적 웹 컨텐츠를 제공하는 응용 소프트웨어
- 일반적으로 웹 서버와 데이터베이스 사이에서 작동함
- 예시: Spring Boot, Node.js Express 등의 프레임워크로 개발한 서버
Servlet
동적 웹 컨텐츠를 제공하는 자바 서버 컴포넌트
- HTTP 통신을 제공하고, 세션 변수나 쿠키 등을 활용할 수 있음
- 서블릿을 구동하기 위해 웹 컨테이너가 필요함
- 웹 컨테이너(서블릿 컨테이너): 서블릿을 관리하는 웹 서버 내 요소
- 웹 컨테이너 서버: 웹 컨테이너를 가진 웹 서버 (e.g. Apache Tomcat, GlassFish, Jetty)
- JSP를 통해 생성할 수도 있음
- JSP: 자바 코드를 통해 동적으로 HTML 등의 문서를 생성하는 기술
인증과 인가
- 인증(Authentication): 시스템 사용자의 신원을 검증하는 행동
- 인가(Authorization): 리소스에 대한 접근 권한을 지정하는 행동
JWT(JSON Web Token)
JSON 형식의 웹 토큰
- 사용자 인증 정보를 전달하기 위한 목적
- Stateless 구조에서, 인증 서버에서 토큰을 발급하고 토큰에 담긴 신원 정보를 신뢰하면, 인증 서버로 추가적인 정보를 물을 필요가 없어짐
- Header와 Payload, Signature로 이루어짐
- Header: Signature를 생성하는 데에 사용한 알고리즘 명시
- Payload: Claim의 집합
- Claim: 토큰의 정보를 담기 위한 key-value 필드
- Signature: 토큰의 유효성을 입증하기 위해 Header와 Payload를 암호화한 것
OpenID
외부 서비스에서의 안전한 접근 권한 인증을 위한 표준 프로토콜
- 사용자 계정의 정보를 서드파티 앱에 제공함
- OIDC(OpenID Connect): 3세대 OpenID 기술, OAuth2를 기반으로 작동함
OAuth
외부 서비스에서의 안전한 접근 권한 인가를 위한 표준 프로토콜
- 서드파티 앱에서 사용자의 권한으로 API를 호출할 수 있도록 만듬
- OAuth 2.0: 권장되는 OAuth 버전, 다양한 플랫폼을 위한 인가 플로우를 제공함
액세스 토큰 재발급
- OAuth2는 두 가지 종류의 토큰(JWT)을 발급함
- Access token: API 접근에 사용되는 토큰, 유효기간이 몇 초 정도로 매우 짧음
- Refresh token: Access token을 발급하기 위해 사용되는 토큰, 유효기간이 몇 주 정도로 김
- 서드파티 앱에서 Access token이 유출되면 위험하므로, 해당 경우 Refresh token을 사용해야 함
- Refresh token 없이 사용자에게 반복적인 로그인을 안내함으로써 보안을 높일 수도 있음
OpenID vs OAuth
- 인증만을 필요로하는 경우, OpenID를 활용하는 편이 더 안전함
MVC 패턴
Model-View-Controller 구조의 GUI 디자인 패턴
- 사용자 인터페이스로부터 비즈니스 로직을 분리할 수 있음 (서로 영향 없이 발전할 수 있음)
Model
: 애플리케이션 로직 수행
View
: 정보 표현
Controller
: 사용자 명령을 View
나 Model
로 전달
- 한계: 각 컴포넌트들이 완전히 독립되지 못 함 (서로 영향을 주어야 하므로 의존적이게 됨)
MVVM 패턴
MVC 패턴의 한계를 보완한 GUI 디자인 패턴
View
를 추상화한 ViewModel
을 중재자로 둠
View
는 ViewModel
의 변경을 감지하고 반영함 (data binding)
ViewModel
은 Model
과 상호작용함 (비즈니스 로직)
View
와 Model
이 서로 의존하지 않게 됨
- 단점: 규모가 커지면
ViewModel
을 운용할 때 성능 문제가 발생함