디지털 암호화를 이용해 도청이나 위조로부터 HTTP 트랜잭션을 안전하게 보호하는 가장 보편적인 기술이다.
어플리케이션 계층과 전송 계층의 사이에 존재해 HTTP 메시지를 TCP로 보내기 전에 먼저 그것들을 암호화하는 보안 계층으로 보낸다.
사용자들은 웹 트랜잭션을 중요한 일에 사용한다. 강력한 보안이 없다면, 결제 정보나 민감한 정보를 전송하지 못할 것이다. 따라서 안번한 방식의 HTTP가 필요하다.
HTTPS를 사용할 때, 모든 HTTP요청과 응답 데이터는 네트워크로 보내지기 전에 암호화된다. HTTPS는 HTTP의 하부에 안전 소켓 계층(Secure Sockets Layer, SSL) 혹은 그를 계승한 전송 계층 보안(Transport Layer Security, TLS)를 이용해 구현된다.
클라이언트는 웹 리소스에 대한 트랜잭션 수행을 요청받으면 URL의 스킴을 검사한다.
만약 URL이 http스킴을 가지고 있다면, 클라이언트는 서버에 80(기본값) 포트로 연결하고 평범한 HTTP 명령을 전송한다.
만약 URL이 https스킴을 가지고 있다면, 클라이언트는 서버에 443(기본값) 포트로 연결하고 서버와 바이너리 포맷으로 된 몇몇 SSL 보안 매개변수를 교환하면서 “핸드셰이크”를 하고, 암호화된 HTTP 명령이 뒤를 잇는다.
암호화되지 않은 HTTP에서, 클라이언트는 웹 서버의 80번 포트로 TCP 커넥션을 열고, 요청 메시지를 보내고, 응답 메시지를 받고, 커넥션을 닫는다. HTTPS에서의 절차는 SSL 보안 계층 때문에 약간 더 복잡하다.
HTTPS에서, 클라이언트는 먼저 웹 서버의 443 포트(보안 HTTP의 기본 포트)로 연결한다.
일단 TCP 연결이 되고 나면, 클라이언트와 서버는 암호법 매개변수와 교환 키를 협상하면서 SSL 계층을 초기화한다.
핸드셰이크가 완료되면 SSL 초기화는 완료되며, 클라이언트는 요청 메시지를 보안 계층에 보낼 수 있다.
이 메시지는 TCP로 보내지기 전에 암호화된다.
SSL Handshake
암호화된 HTTP 메시지를 보낼 수 있게 되기 전에, 클라이언트와 서버는 SSL 핸드셰이크를 할 필요가 있다. 핸드셰이크에서는 다음과 같은 일이 일어난다.
프로토콜 버전 번호 교환
양쪽이 알고 있는 암호 선택
양쪽의 신원을 인증
채널을 암호화하기 위한 임시 세션 키 생성
암호화된 HTTP 데이터가 네트워크를 오가기 전에, SSL은 통신을 시작하기 위해 상당한 양의 핸드셰이크 데이터를 주고받는다.
소켓 계층(Secure Sockets Layer, SSL) 혹은 그를 계승한 전송 계층 보안(Transport Layer Security, TLS)
data → SSL length + MAC이 붙어있다.
암호화 - 복호화를 같은 키를 사용하는 것이다. 대칭키 암호에서, 발송자와 수신자 모두 통신을 위해 비밀키를 똑같이 공유할 필요가 있다. 발송자와 수신자 모두 통신을 위해 비밀키를 똑같이 공유할 필요가 있다.
발송자는 공유된 비밀 키를 메시지를 암호화하고 그 결과인 암호문을 수신자에게 발송하기 위해 사용한다.
수신자는 역시 암호문을 받은 뒤 같은 공유된 키를 사용해 원래의 평문을 복원하기 위해 해독 함수를 적용한다.
퍼블릭키 - 프라이빗 키를 사용해 암호화 하는 것
한 쌍의 호스트가 하나의 인코딩 / 디코딩 키를 사용하는 대신, 공개키 암호 방식은 두 개의 비대칭 키를 사용한다. 하나는 호스트의 메시지를 인코딩하기 위한 것이고, 하나는 그 호스트의 메시지를 인코딩하기 위한 것이며, 다른 하나는 그 호스트의 메시지를 디코딩하기 위한 것이다. 인코딩 키는 모드를 위해 공개되어 있고, 프라이빗 키는 호스트 만이 알고 있다.
서명은 메시지를 작성한 저자가 누구인지 알려준다. 저자는 저자의 극비 개인키를 가지고 있기 때문에, 오직 저자만이 이 체크섬을 계산할 수 있다. 체크섬은 저자의 개인 서명처럼 동작한다.
서명은 메시지 위조를 방지한다. 만약 악의적인 공격자가 송신중인 메시지를 수정했다면, 체크섬은 더 이상 그메시지와 맞지 않을 것이다. 그리고 체크섬은 저자의 비밀 개인키에 관련되어 있기 때문에, 침입자는 그 위조된 메시지에 대한 올바른 체크썸을 날조해낼 수 없을 것이다.
서명된
메시지를 보낸다.이 방법은 HTTPS에서도 사용되는데, 처음에 대칭키를 교환할 때 사용한다.
대칭키는 비대칭 키보다 비교적 연산의 비용이 적기 때문에 실제 메시지를 주고 받을 때에는 대칭키를 사용한다.
도메인 이름과 IP 주소에 대한 정보를 관리하는 시스템이다.
DNS 덕분에 인터넨 사용자들은 IP주소를 일일이 외우지 않아도 된다.
서버를 분리해서 계층적으로 관리, 트래픽과 데이터를 분산함. 트리 구조로 나타낼 수 있다.
루트 도메인 → Top-Level-Domain → Second Level Domain → Third level DOmail
(Root NS → TLD NS → SubDomain NS)
으로, recursive형태로 움직인다.
상위 서버는 하위 서버의 주소를 알고, 하위 주소를 보내준다.
우리가 실제로 요청하는 것은 DNS 리커서(로컬 DNS 서버) → 로컬 DNS에서 처리해서 클라이언트에게 IP 주소를 response한다.
빠른 속도와 연결 유지의 불필요성 때문이다 .
TCP의 경우 데이터 전송 시작 전에 3-way-handshaking 과정이 있는 반면 UDP는 연결 설정에 드는 비용이 없다. DNS는 신뢰성보다 속도가 더 중요한 서비스이기 때문에 TCP보다 UDP가 더 적합하다.
또한, UDP는 512 bytes를 넘어가지 않는 패킷만 전송이 가능하고 오버헤드가 없어서 속도가 빠른데, DNS가 전송하는 데이터 패킷 사이즈가 매우 작고 신뢰성이 보장되지 않아도 되므로 UDP가 유리하다.
UDP는 어떤 정보도 기록하지 않고, 유지할 필요도 없다.따라서 DNS 서버는 TCP보다 많은 클라이언트를 수용할 수 있으므로 연결 상태를 유지하지 않고 정보 기록을 최소화할 수 있는 UDP를 채택하였다.
DNS 서버가 해당 패킷을 받았을 때 어떤 식으로 처리할 지를 나타내는 지침이다. DNS 상에서 도메인에 관한 설정을 하기 위해 사용되는 문자이다. DNS 레코드에는 서버가 요청에 응답하는 방법에 대한 다양한 구문과 명령이 포함되어 있다.
대표적인 종류에는 A, CNAME, NS가 있다.
A → IPv4 주소 매칭
CNAME → 도메인 이름에 대한 별칭으로, A를 가리킨다.
CNAME → A → IP 주소
NS →도메인 이름에 대한 권한이 있는 네임 서버를 매핑한다. 이를 통해 다른 네임 서버에 도메인 이름에 대한 권한을 위임해줄 수 있다.
어플리케이션 계층의 프로토콜이다.
특징
클라이언트 - 서버 프로토콜
클라이언트 - 서버의 구조로 이루어져 요청 - 응답을 주고받는다.
무상태 프로토콜 (Stateless)
HTTP에서는 서버가 클라이언트의 상태를 보존하지 않는다.
따라서 응답과 요청이 독립적이다.
장점 : 확장성이 높다.무상태는 응답 서버를 쉽게 바꿀 수 있기 때문에 무한한 서버 증설이 가능하다.(스케일 아웃)
단점 : 클라이언트가 추가 데이터를 전송해야 한다.
대표적으로 로그인에서 쿠키 , 세션, 토큰 등을 이용해 상태를 유지해야 한다.
비연결성을 가지는 HTTP에서는 실제로 요청을 주고받을 때만 연결을 유지하고 연결을 끊는다 이를 통해 최소한의 자원으로 서버를 유지할 수 있다.
이 때문에 리소스가 많은 페이지에서는 연결의 비용이 높게 들고, 따라서 HTTP 지속 연결에서는 연결이 이루어지고 난 뒤 각각의 자원들을 요청하고, 모든 자원에 대한 응답이 돌아온 후에 연결을 종료하는 방식으로 보완했다.
GET
클라이언트에서 서버로 리소스 요청할 때 쓴다
멱등성 O 안전성 O 캐시 가능 body x
브라우저 히스토리에 남는다.
길이 제한이 있다.
쿼리스트링으로 파라미터를 넘긴다.
POST
멱등성 X 사용 안전성 X 캐시 가능은 하지만 사용 X
길이 제한이 없고, 데이터를 body에 담아서 보낸다.
브라우저 히스토리가 남지 않는다.
멱등성 - 여러번 요청에 대한 서버의 상태가 같은가
안전한 메서드 - 호출해도 리소스가 변경되지 않는가
둘다 리소스를 수정할 때 쓰인다.
100~ 정보 응답
200 ~ 성공 응답
300 ~ 리다이렉션 응답
400 ~ 클라이언트 에러 응답
500 ~ 서버 에러 응답
대표적인 코드
200 OK. 성공
201 POST & PUT 성공
404 NOT FOUND
400 잘못된 요청
500 서버 에러
HTTP 헤더는 요청이나 응답에 관해서 부가적인 정보를 전달하는 HTTP 요청 또는 응답 필드이다.
대표적인 헤더
Access-Control-Allow-Origin
CORS와 관련된 HTTP 응답 헤더
다른 도메인에서의 요청을 허용하는 경우 어떤 도메인에서 요청을 허용할 것인지를 명시한다.
이를 통해 브라우저는 해당 도메인에서 온 요청만 해당 자원에 접근하도록 허용하게 된다.
Cache-Control: no-cache
캐시 관리자에게 캐싱을 허용하나, 사용 전 필수로 Server에 유효성 체크를 해야 함.
Cache-Control: no-store
캐싱을 금지함.
Cache-Control: max-age=3600
초 단위로 캐시가 유효한 시간을 제공한다. 시간이 지나면 캐시가 삭제된다.
Cache-Control: must-revalidate
캐시 관리자에게 내부 유효성 체크를 허용하지 않으며, 항상 Server에 유효성 체크를 하도록한다.
Next.js에서는 fetch API를 오버라이드하여 캐시 컨트롤을 인자값으로 넣을 수 있도록 하고,
페이지 GET 요청 시에는 자동적으로 캐시 되도록 디폴트 값도 변경함.
하나의 Connection 으로 다수의 Request 와 Response 를 처리할 수 있게끔 해서 네트워크 비용을 줄이는 방식이다.
하지만 위의 기법 설명에서 언급하듯이, 결국 완전한 멀티플렉싱이 아닌 응답처리를 미루는 방식이므로 각 응답의 처리는 순차적으로 처리되며, 결국 후순위의 응답은 지연될 수 밖에 없다.
이는 HTTP의 Head Of Line Blocking 이라 부르며 Pipelining 의 큰 문제점이다.
따라서 HTTP/1.1 의 웹서버는 서버측에 Multiplexing 을 통한 요청의 처리를 요구하며, 각 Connection 당 요청과 응답의 순서가 보장되는 통신을 한다.
HTTP 파이프라이닝은 HTTP/2 가 등장하면서 멀티플렉싱 알고리즘으로 대체되었고, 모던 브라우저들에서도 기본적으로는 활성화하지 않고 있다.