HTTP란?
HyperText Transfer Protocal
웹에서 브라우저와 서버가 통신하기 위한 포로토콜(규약)
→ 브라우저가 사이트에 접속할 때 서버에서 웹페이지를 구성하는 데이터 (HTML, CSS, JavaScript 등)을 주고받는 규칙
요청(Request)와 응답(Response)의 형태로 진행된다.
- HTTP의 특징
- 커넥션당 하나의 요청과 응답만 처리
- 즉, 여러개의 요청을 한번에 전송/응답할 수 없다.
- 기본 80번 포트 사용
- 무상태성
- 서버가 클라이언트의 상태를 보존하지 않기에 로그인과 같이 유저의 상태를 유지해야하는 서비스일 경우 브라우저 쿠키, 서버 세션, 토큰 등을 이용해 상태를 유지해야 한다.
- 비연결성
- 기본적으로 연결을 유지하지 않기에 요청을 보낼 때마다 연결했다 끊는 작업을 반복한다.
- 각각의 자원을 다운로드하기 위해 연결과 종료를 반복하는 비효율이 생긴다.
- 트래픽이 많지 않고 빠른 응답을 제공할 수 있는 경우 효율적이지만 트래픽이 많고 큰 규모의 운영을 할 때는 한계를 가진다.
- HTTP의 한계
- 데이터가 전혀 암호화되어 있지 않은 평문 통신이다.
- 중간에서 통신 내용을 엿보거나 가로채는 공격이 가능하다.
- 스니핑
- 네트워크상에서 다른 사용자들이 주고받는 패킷(데이터 조각)을 몰래 엿보거나 도청하는 해킹 기법
- 중간자 공격
- 두 통신 당사자 사이에 공격자가 몰래 끼어들어 중계하는 공격
- HTTP 흐름
- 브라우저 주소창에 URL을 입력한다.
- DNS 조회
- 도메인 주소(예: www.naver.com)를 실제 서버의 IP 주소로 바꾼다.
- TCP 연결
- 3-way handshake로 브라우저와 서버가 연결을 맺는다.
- HTTPS라면 이후 TLS 핸드셰이크까지 진행한다.
- HTTP 요청
- 브라우저가 서버에 요청 메시지를 보낸다.
- 요청 메시지는 요청 라인(메서드, 경로, 버전), 헤더, 바디로 구성된다.
- HTTP 응답
- 서버가 요청을 처리하고 응답 메시지를 보낸다.
- 응답 메시지는 상태 라인(버전, 상태 코드), 헤더, 바디로 구성된다.
- 렌더링
- 브라우저가 받은 HTML, CSS, JS를 해석해 화면에 그린다.
- 이후 연결은 버전에 따라 유지되거나 종료된다.
- HTTP 요청 메서드
- 클라이언트가 서버에게 어떤 동작을 원하는지 알려주는 방법이다.
- 주요 메서드
- GET
- 리소스를 조회한다.
- 데이터를 URL의 쿼리 스트링에 담아 보내기 때문에 주소창에 노출된다.
- POST
- 데이터를 서버에 보내 새로운 리소스를 생성한다.
- 데이터를 바디에 담아 보낸다.
- PUT
- 리소스 전체를 교체한다. 리소스가 없으면 새로 생성한다.
- PATCH
- 리소스의 일부만 수정한다.
- DELETE
- 리소스를 삭제한다.
- OPTIONS
- 서버가 지원하는 메서드를 확인한다.
- CORS의 사전 요청(Preflight)에 사용된다.
- 멱등성
- 같은 요청을 여러 번 보내도 결과가 같은 성질이다.
- GET, PUT, DELETE는 멱등하고 POST는 멱등하지 않다.
- 예) 게시글 작성 POST를 3번 보내면 게시글이 3개 생긴다.
- HTTP 응답 상태 코드
- 상태 코드는 클라이언트가 보낸 요청의 처리 상태를 응답에서 알려주는 기능으로서, 3자리 숫자로 만들어져 있으며, 100 ~ 500 번대 숫자로 이루어져 있다.
- 1xx (정보)
- 요청을 받았고 처리 중이라는 의미다. 실무에서 직접 볼 일은 거의 없다.
- 2xx (성공)
- 200 OK: 요청 성공
- 201 Created: 요청이 성공해 새로운 리소스가 생성됨 (주로 POST)
- 204 No Content: 요청은 성공했지만 돌려줄 데이터가 없음 (주로 DELETE)
- 3xx (리다이렉션)
- 301 Moved Permanently: 리소스가 영구적으로 다른 주소로 이동함
- 302 Found: 리소스가 일시적으로 다른 주소로 이동함
- 304 Not Modified: 리소스가 변경되지 않았으니 브라우저 캐시를 사용하라는 의미
- 4xx (클라이언트 오류)
- 400 Bad Request: 요청 형식이 잘못됨
- 401 Unauthorized: 인증이 필요함 (로그인 안 된 상태)
- 403 Forbidden: 인증은 됐지만 권한이 없음
- 404 Not Found: 요청한 리소스가 없음
- 5xx (서버 오류)
- 500 Internal Server Error: 서버 내부에서 오류가 발생함
- 502 Bad Gateway: 중간 서버(게이트웨이)가 잘못된 응답을 받음
- 503 Service Unavailable: 서버 과부하나 점검으로 일시적으로 요청을 처리할 수 없음
HTTP의 버전별 비교
HTTP/1.1
- 지속 연결
- keepalive 라는 기능이 추가되어 연결이 이루어지고 난 뒤 각각의 자원들을 요청하고, 모든 자원에 대한 응답이 돌아온 후에 연결을 종료한다.
- HOL(Head-of-Line) Blocking
- 앞 요청의 응답이 늦으면 뒤 요청도 줄줄이 대기하는 문제 발생
HTTP/2.0
- 다중 요청/응답 가능
- 커넥션당 여러개의 요청과 응답을 주고받을 수 있다.
- HTTP/2.0은 여러 리소스의 동시 전송이 가능하므로 HTTP/1.1에 비해 페이지 로드 속도가 약 50% 정도 빠르다고 알려져 있다.
HTTP/3.0
- QUIC 프로토콜 기반: TCP 대신 UDP 위에서 동작
- TCP
- 보낸 데이터를 확실히 받았는지 확인하면서 보내는 방식
- 데이터가 빠짐없이, 순서대로 도착
- 확인 절차가 많아서 느림
- UDP
- 데이터를 받았는지 확인 없이 되는대로 응답을 보내는 방식
- 확인 절차가 없어서 매우 빠름
- 데이터가 빠지거나 순서가 뒤섞일 수 있음
- QUIC은 UDP 위에서 재전송·순서 보장을 직접 해준다
- TCP HOL Blocking 해결: 스트림이 독립적이라 한 스트림의 패킷이 유실돼도 다른 스트림은 영향을 받지 않음
HTTPS란?
보안이 강화된 HTTP 프로토콜로 HTTPS 의 S는 Secure를 의미한다.
- HTTPS의 특징
- HTTP 통신 내용을 SSL 또는 그 후속 기술인 TLS 프로토콜을 이용해 암호화 한다.
- 기본 443번 포트 사용
- 아래 3가지 핵심 목표를 가진다
- 기밀성
- 데이터를 암호화해서 제 3자가 데이터를 훔쳐보더라도 내용을 해석할 수 없도록 한다.
- 무결성
- 전송 중에 데이터가 변조되지 않았음을 보장
- 누군가 내용을 바꾸면 받는 쪽에서 알아챌 수 있다.
- 인증
- 인증서를 통해 지금 접속한 서버가 위조되지 않은 진짜 서버임을 보장한다.
- SSL/TLS 핸드셰이크
- 브라우저와 서버가 본격적으로 암호화 통신을 시작하기 전에 서로를 확인하고 데이터 암호화 규칙을 정하는 과정
- SSL/TLS 핸드셰이크 과정
- Client Hello
- 클라이언트가 서버에 연결을 요청하며 아래 정보를 보낸다.
- 지원하는 TLS 버전
- 사용 가능한 암호화 방식 목록
- 클라이언트 랜덤 값
- Server Hello
- 서버가 응답하며 아래 정보를 보낸다.
- 클라이언트가 보낸 목록 중 서버가 선택한 TLS 버전과 암호화 방식
- 서버 랜덤 값
- Certificate
- 서버가 자신의 SSL 인증서를 보낸다.
- 인증서 안에는 서버의 공개키와 도메인 정보, CA의 전자서명이 들어 있다.
- 이후 Server Hello Done 메시지로 서버 쪽 전송이 끝났음을 알린다.
- 인증서 검증
- 클라이언트는 받은 인증서가 믿을 수 있는지 확인한다.
- 브라우저에 내장된 신뢰할 수 있는 CA가 서명했는지
- 유효 기간이 지나지 않았는지
- 인증서의 도메인이 접속한 주소와 일치하는지
- 검증에 실패하면 브라우저가 경고 화면을 띄운다.
- Client Key Exchange
- 클라이언트가 Pre-Master Secret이라는 랜덤 값을 새로 만든다.
- 이 값을 인증서에 들어 있던 서버의 공개키로 암호화해서 서버에 보낸다.
- 공개키로 암호화한 값은 서버의 개인키로만 풀 수 있기 때문에, 중간에서 가로채도 내용을 알 수 없다.
- 세션키 생성
- 서버는 자신의 개인키로 Pre-Master Secret을 복호화한다.
- 이제 클라이언트와 서버는 같은 재료 3개를 갖게 된다.
- Client Random + Server Random + Pre-Master Secret
- 양쪽이 이 재료로 각자 같은 계산을 해서 동일한 세션키(대칭키)를 만든다.
- 세션키 자체는 네트워크로 전송되지 않는다.
- Finished
- 양쪽이 "이제부터 세션키로 암호화한다"는 신호를 보낸다.
- 그동안 주고받은 핸드셰이크 내용을 세션키로 암호화한 Finished 메시지를 서로 보내 확인한다.
- 양쪽이 정상적으로 복호화되면 핸드셰이크가 완료된다.
- 암호화 통신 시작
- 이후 모든 HTTP 데이터는 세션키(대칭키)로 암호화해서 주고받는다.
- SSL 인증서의 중요성
- 인증서 기반 통신이 안전한 이유는 신뢰할 수 있는 제3자, 즉 인증 기관이 존재하기 때문
- 브라우저는 이 SSL 인증서를 확인할 때 코모도/고대디 같은 공신력 있는 인증 기관에서 발급한 것이 맞는지 브라우저에 내장된 인증 기관 목록과 비교해 철저히 검사한다.
- 만약 공격자가 만든 가짜 인증서라면 브라우저는 즉시 ‘이 사이트는 안전하지 않습니다’라는 경고창을 띄우고 접속을 차단한다.
- 검증 과정을 통과했다는 것은 현재 접속한 웹 사이트는 사칭된 웹 사이트가 아니라 진짜 해당 회사나 기관이 운영하는 진짜 서버라는 뜻이 된다.
- SSL 인증서는 암호화에 사용되는 공개키를 안전하게 전달하는 역할과 동시에, 접속하려는 서버의 신원을 확실하게 증명하는 역할을 한다. 이 2가지가 결합되어 HTTPS 통신은 높은 수준의 보안을 유지할 수 있다.
- 비대칭키와 대칭키를 섞어 쓰는 이유
- 비대칭키(공개키/개인키)
- 키를 안전하게 전달할 수 있지만 연산이 느림
- 대칭키(세션키)
- 연산이 빠르지만 같은 키를 양쪽이 안전하게 나눠 갖기 어려움
- 그래서 핸드셰이크에서만 비대칭키를 써서 대칭키 재료를 안전하게 전달하고, 실제 데이터는 빠른 대칭키로 암호화
- Mixed Content
- HTTPS 페이지에서 HTTP 리소스를 불러오면 브라우저가 차단하거나 경고
- HSTS
- 브라우저가 해당 도메인에 항상 HTTPS로만 접속하도록 강제하는 헤더