브라우저를 이용해 https://www.google.com에 접속하면 무슨 일이 벌어질까?
큰 흐름
- 브라우저, 운영체제에서 도메인명이 캐쉬 되어있는지 확인하고 없으면 DNS로 도메인명에 해당하는 ip주소를 요청한다.
- 받아온 ip 주소를 이용해 브라우저는 Resquest 메세지를 만들어 운영체제에 부탁한다.
- 브라우저로 부터 메세지를 받은 운영체제의 프로토콜 스택은 메세지를 패킷 속에 저장하고, 수신처 주소 같은 제어 정보들을 덧붙인다.
- LAN, 허브, 스위치, 라우터들을 통해 목적지로 운반된다.
- 캐시 서버가 있다면 굳이 웹 서버까지 가지 않아도 되는지 판단하고 데이터를 바로 받아온다.
- 웹 서버에 도착하면 웹서버의 프로토콜 스택이 패킷을 추출하여 메시지를 복원하고 웹 서버 어플리케이션에 넘긴다.
- 응답메세지를 넣어 클러이언트로 전송!
조금 더 자세히 살펴보자.
https://www.google.com/로 요청을 보낼 때 URL 맨 앞단에 보면 https 통신 방법을 사용하고 있는 것을 알 수 있다.
HTTPS
HTTPS는 사실 하나의 프로토콜이라기보다는 HTTP 통신을 SSL/TLS를 거쳐 진행한다고 생각하면 된다. HTTP 같은 경우는 올바른 곳 에서 온건지, 받은 데이터가 올바른 것인지를 확인할 수가 없어 보안에 취약하다. 이런 취약점을 보완한 것이 HTTPS다.
간단히 개념들을 먼저 보면,
대칭키
암호화를 생각 할 때 가장 간단하게 생각해본다면, 서로 키를 공유하면 된다. 예를 들어, A가 키를 이용해 데이터를 암호화해서 B에게 보내면 B는 다시 공유하고있는 키를 이용해 복호화한다. 이 과정은 단순하고 강력하지만, 서로간에 키를 공유해야한다.
공개키
공개키는 누구에게나 제공 되지만 이 공개키를 이용해 암호화된 데이터는 특정한 개인키로만 복호화 할 수 있다. 보통 대칭키 방식보다 복잡하며, 리소스가 많이 들어가게 된다.
HTTPS는 위의 두 가지 방법을 모두 사용한다.
- 클라이언트에서 랜덤데이터를 생성한다. 이 데이터는 후에 암호화에 사용된다. 그리고 자신이 어떤 암호화 방식이 가능한지에 대한 정보를 서버로 전송한다.
- 서버 쪽에서는 클라이언트 쪽에서 이용 가능한 암호화 방식을 선택하고 이를 이용해 정보를 교환한다. 서버에서도 역시 랜덤데이터를 만든다. 그리고, 만들어진 랜덤 데이터와 인증서를 포함하여 다시 응답한다.
- 클라이언트는 내장된 CA LIST를 이용해 서버가 보내온 인증서가 CA(Certificate authority)에 의해 발급된 것인지 확인한다. 확인이 되었다면 서버에서 보내온 랜덤데이터와 앞에서 만든 클라이언트의 랜덤데이터를 이용해 pre master key를 만들고 인증서에 담긴 공개키를 이용해 pre master key를 서버로 보낸다. 그리고 서로 가진 pre master key는 일련의 과정을 통해 master key로 만들어진다.
신뢰할만한 제 3자 (CA)가 제공하는 인증서를 통해 올바른 서버인지 확인하고, 공개키 방식을 이용해 대칭키를 나눠 가진다고 생각하면 되겠다.
조금더 자세히 살펴보자.
HTTP는 대부분 TCP를 기반으로 통신한다.
TCP
TCP는 신뢰도가 높은 통신이다. 일단 던지고 보는 UDP와는 달리, 연결이 되었는지 확인하는 작업을 먼저 거친다(Handshaking). 이 후에는 패킷 번호를 통해 중간에 데이터가 유실 되지는 않았는지 확인하는 작업을 거치고 재요청, 재발송이 이뤄지기도 한다.
- 클라이언트가 서버로 요청을 보내면서 Handshake 과정이 시작된다. 이 요청은 header에 난수로 이뤄진 Sequence Number, 그리고 에 SYN flag가 1로 설정되어 보내진다.
- 서버 쪽에서 요청을 받으면 받은 Sequence Number에 +1을 하고, SYN flag와 ACK flag를 1로 설정해 응답을 보낸다.
- 클라이언트는 다시, Sequence Number +1 그리고 ACK flag를 1로 설정하여 응답한다. 여기까지가 3-way-handshake 과정이다. 이 과정으로 서로 안전하게 연결되었다는 것을 확인 했고, 데이터를 보내기 시작한다.
- TCP는 신뢰도가 높은 통신이다. 하나의 패킷을 보내면 그 패킷이 잘 도착했는지 응답하고 확인하는 과정을 거친다. 그런데 이과정을 하나하나 순차적으로 하면 많은 시간이 걸리게 된다. 그래서 TCP는 window sliding을 이용해 일정 범위의 모든 패킷을 한 번에 요청하고 앞의 패킷의 응답이 도착하면 서서히 window sliding 구간을 오른 쪽으로 옮겨간다.
- 통신이 끝날때는, 앞에 3-way-handsake과정과 비슷하게 4-way-handshake 과정을 거친다. 먼저 클라이언트에서 FIN flag를 전송한다.
- 서버에서는 ACK flag를 통해 확인 메세지를 전달하고, close_wait 상태가 된다.
- 서버에서 다시 FIN flag를 클라이언트에게 전달하고, 종료 프로세스를 진행한다.
- 클라이언트는 다시 ACK flag를 서버로 보낸후 TIME_WAIT 상태가 된다. TIME_WAIT 에서 일정 시간이 지나면 closed된다. ACK 받은 서버도 closed!
- 여기서 먼저 요청을 보내는 쪽이 서버가 될 수도 있다.
- 마지막에 TIME_WAIT이 필요한 이유는 크게 두 가지다. 지연 패킷이 발생 했을 때, 그리고 마지막 ACK 유실로 LAST_ACK 상태가 유지 되어 새로운 SYN 패킷 전달에 오류가 생기는 등의 오류를 막기 위함이다.
Browser
어렵게 어렵게 https://www.google.com로 HTML 파일을 받아왔다. 이후에는 브라우저에서 HTML을 해석해서 렌더한다. 이거는 다음에 다시 자세하게 정리하자…
- 태그들을 토큰화하고 파싱해서 DOM Tree 생성
- DOM과 마찬가지로 CSS를 파싱해서 CSSOM 생성
- DOM과 CSSOM 연결해서 Render Tree 생성
- 노드들이 그려질 위치와 크기를 계산해서 배치 (Layout)
- 화면에 그리기
그렇게, 요청 했던 google 메인 화면이 브라우저에 짠