보안

보안 #

WebRTC는 어떤 보안을 제공하나요? #

모든 WebRTC 연결은 인증되고 암호화됩니다. 제3자가 당신이 보내는 내용을 엿보거나 가짜 메시지를 삽입할 수 없습니다. 또한 세션 설명(Session Description)을 생성한 바로 그 WebRTC 에이전트와 통신하고 있음을 보장할 수 있습니다.

이 메시지들이 변조되지 않는 것이 매우 중요합니다. 전송 중 세션 설명을 제3자가 읽는 것은 괜찮지만, WebRTC는 그 내용이 수정되는 것에 대해 자체 보호 장치가 없습니다. 공격자는 ICE 후보를 바꾸고 인증서 지문을 바꿔 중간자 공격을 시도할 수 있습니다.

어떻게 동작하나요? #

WebRTC는 두 가지 기성 프로토콜을 사용합니다. Datagram Transport Layer Security(DTLS)와 Secure Real-time Transport Protocol(SRTP)입니다.

DTLS는 두 피어 간에 세션을 협상하고 데이터를 안전하게 교환할 수 있게 합니다. HTTPS에 쓰이는 TLS의 형제 격 기술이지만, DTLS는 전송 계층으로 TCP 대신 UDP를 사용하므로 비신뢰성 전달을 자체적으로 처리해야 합니다. SRTP는 미디어를 안전하게 교환하도록 특화된 프로토콜로, DTLS 대신 사용할 때 가능한 최적화가 있습니다.

DTLS가 먼저 사용됩니다. ICE로 마련된 연결 위에서 핸드셰이크를 수행합니다. DTLS는 클라이언트/서버 프로토콜이므로 한쪽이 핸드셰이크를 시작해야 합니다. 이 역할은 시그널링 단계에서 결정됩니다. DTLS 핸드셰이크 중 양쪽은 인증서를 제시합니다. 핸드셰이크가 끝나면 이 인증서를 세션 설명에 있는 인증서 해시와 비교합니다. 기대한 WebRTC 에이전트와 핸드셰이크가 이루어졌는지 확인하기 위함입니다. 이후 이 DTLS 연결은 DataChannel 통신에 사용됩니다.

SRTP 세션을 만들 때는 DTLS가 생성한 키로 초기화합니다. SRTP는 핸드셰이크 메커니즘이 없으므로 외부 키로 부트스트랩해야 합니다. 준비가 끝나면 SRTP로 암호화된 미디어 교환이 시작됩니다!

보안 101 #

이 장의 기술을 이해하려면 먼저 다음 용어를 알아야 합니다. 암호학은 까다로운 주제이므로 다른 자료도 함께 참고하길 권합니다.

평문과 암호문 #

평문(plaintext)은 암호화기의 입력, 암호문(ciphertext)은 출력입니다.

암호(Cipher) #

암호는 평문을 암호문으로 변환하는 절차입니다. 이 절차는 역으로 적용 가능하여 암호문을 평문으로 되돌릴 수 있습니다. 대부분의 암호는 동작을 바꾸는 ‘키’를 사용합니다. 흔히 말하는 암호화/복호화입니다.

간단한 예로 ROT13이 있습니다. 각 문자를 13글자씩 밀어내는 방식입니다. 되돌릴 때는 13글자 뒤로 이동합니다. 평문 HELLO는 암호문 URYYB가 됩니다. 이 경우 암호는 ROT, 키는 13입니다.

해시 함수 #

해시 함수는 일방향으로 동작하여 다이제스트를 생성합니다. 같은 입력에 대해 항상 같은 출력이 나오며, 출력으로부터 입력을 역으로 알아낼 수 없어야 합니다. 해시는 메시지가 변조되지 않았음을 확인할 때 유용합니다.

아주 단순한 해시 예로 ‘한 글자 건너뛰기’를 생각해볼 수 있습니다. HELLOHLO. 이 값만으로 입력이 HELLO였다고 단정할 수는 없지만, HELLO가 이 해시와 일치하는지는 확인할 수 있습니다.

공개키/개인키 암호 #

DTLS와 SRTP가 사용하는 암호 방식입니다. 공개키와 개인키 두 개의 키를 사용합니다. 공개키는 메시지 암호화에 쓰이며 공유해도 안전합니다. 개인키는 복호화에 사용하며 절대 공유하면 안 됩니다. 공개키로 암호화된 메시지는 개인키로만 복호화할 수 있습니다.

디피-헬먼 교환 #

디피-헬먼 교환은 서로 처음 만난 두 사용자가 인터넷을 통해 안전하게 공유 비밀을 만드는 방법입니다. 이는 이산 로그 문제의 난이도에 기댑니다. 이 메커니즘이 DTLS 핸드셰이크를 가능하게 한다는 점만 알아두면 충분합니다.

자세한 설명은 위키피디아를 참고하세요.

의사난수 함수(PRF) #

의사난수 함수는 겉보기엔 무작위처럼 보이는 값을 생성하는 정해진 함수로, 여러 입력을 받아 단일 출력을 만듭니다.

키 유도 함수(KDF) #

키 유도는 PRF의 한 형태입니다. 더 강한 키를 만들기 위해 사용하는 함수로, 대표적으로 키 스트레칭이 있습니다.

예를 들어 8바이트 길이의 키를 더 강하게 만들고 싶을 때 KDF를 사용할 수 있습니다.

논스(Nonce) #

논스는 암호에 추가로 제공하는 입력입니다. 같은 메시지를 여러 번 암호화하더라도 서로 다른 출력을 얻게 해 줍니다.

같은 메시지를 10번 암호화해도, 논스를 다르게 주면 각기 다른 암호문이 생성됩니다. 이는 패턴 식별이나 재전송 공격을 어렵게 합니다.

DTLS #

DTLS는 TLS와 유사하지만 UDP 위에서 동작합니다. WebRTC에서는 ICE가 만들어 준 연결 위에서 DTLS 핸드셰이크가 진행됩니다. 핸드셰이크를 위해 여러 메시지가 오가며, 성공하면 애플리케이션 데이터 교환이 시작됩니다.

핸드셰이크 절차 #

DTLS 핸드셰이크는 다음과 같은 메시지로 구성됩니다(주요 항목만 요약).

HelloVerifyRequest #

서버가 클라이언트의 출처를 확인하기 위한 응답으로, 재전송 공격 방지에 도움이 됩니다.

ClientHello / ServerHello #

지원하는 프로토콜 버전과 암호군 목록, 랜덤 값 등을 교환합니다. 서버는 선택된 암호군을 통지합니다.

Certificate #

상대에게 자신의 공개키 인증서를 보냅니다.

ServerKeyExchange / ClientKeyExchange #

공개키 교환에 사용됩니다. 핸드셰이크 이후 두 값으로 Pre-Master Secret을 생성합니다.

CertificateRequest #

서버가 클라이언트에게 인증서를 요구할 때 전송합니다(요청 또는 필수).

ServerHelloDone #

서버 측 핸드셰이크 단계가 끝났음을 알립니다.

CertificateVerify #

인증서에 대응하는 개인키를 소유하고 있음을 증명합니다.

ChangeCipherSpec #

이 메시지 이후로는 암호화가 적용됨을 알립니다.

Finished #

암호화된 상태로 전송되며, 지금까지의 모든 메시지 해시를 포함합니다. 핸드셰이크 변조 여부를 검증합니다.

키 생성 #

핸드셰이크가 끝나면 암호화된 데이터 전송을 시작할 수 있습니다. 구체적인 암호군은 ServerHello에서 결정됩니다.

먼저 Pre-Master Secret을 생성합니다. ServerKeyExchangeClientKeyExchange에서 교환한 키로 디피-헬먼 과정을 수행해 얻습니다.

다음으로 Master Secret을 생성합니다. DTLS 버전마다 정의된 의사난수 함수가 있으며, DTLS 1.2에서는 Pre-Master SecretClientHello/ServerHello의 랜덤 값을 입력으로 사용합니다. 이 함수의 출력이 Master Secret이며, 실제 암호에 쓰이는 키가 됩니다.

애플리케이션 데이터 교환 #

DTLS의 주력 메시지는 ApplicationData입니다. 초기화된 암호로 페이로드를 암호화해 송수신하면, 보안 채널이 완성됩니다.

DTLS에는 재협상 등 흥미로운 기능이 더 있지만, WebRTC에서는 사용하지 않으므로 여기서는 다루지 않습니다.

SRTP #

SRTP는 RTP 패킷 암호화를 위해 설계된 프로토콜입니다. 세션을 시작하려면 키와 암호를 지정해야 합니다. DTLS와 달리 자체 핸드셰이크가 없으므로, 필요한 키와 설정은 DTLS 핸드셰이크 과정에서 생성한 것을 사용합니다. DTLS는 다른 프로세스가 사용할 키를 내보내는 API를 제공하며, RFC 5705에 정의되어 있습니다.

세션 생성 #

SRTP는 입력 값에 키 유도 함수를 적용해 실제로 사용할 키를 생성합니다. 세션 생성이 끝나면 미디어 처리를 시작할 수 있습니다.

미디어 교환 #

각 RTP 패킷에는 16비트 SequenceNumber가 있습니다. 이는 패킷 순서를 유지하는 데 사용되며, 통화 중에는 값이 순환합니다. SRTP는 이 순환을 추적하며 롤오버 카운터라고 부릅니다. 패킷을 암호화할 때 SRTP는 롤오버 카운터와 시퀀스 번호를 논스로 사용하여, 같은 데이터를 두 번 보내더라도 암호문이 달라지게 합니다. 이는 패턴 식별 및 재전송 공격을 방지하는 데 중요합니다.