C++/Socket 통신
보안과 암호화된 소켓 통신 - C++
초심을 찾자
2025. 2. 27. 10:44
SMALL
포스팅 계기
이전 글에 이어 2025.02.26 - [C++ 개발이야기/Socket 통신] - 비동기 소켓 프로그래밍 - C++ 비동기 소켓 프로그래밍을 다룬 이후, 네트워크 보안의 중요성도 함께 짚고 넘어갈 필요가 있다고 판단했고 나 또한 잘 모르는 지식이라 공부할 겸 해당 포스팅을 작성하게 되었다. 소켓을 통한 데이터 전송은 다양한 보안 위협에 노출될 수 있으며, 특히 민감한 정보를 주고받을 때 암호화가 필수적이라고 생각한다. 이번 포스팅에서는 보안과 암호화된 소켓 통신의 개념을 설명하고, C++을 이용하여 이를 구현하는 방법을 설명하겠다.
보안과 암호화된 소켓 통신 개념
소켓 통신이란 네트워크를 통해 데이터를 주고받는 방식이다. 그러나 기본적인 소켓 통신은 데이터를 평문(Plain Text)으로 전송하기 때문에 보안에 취약할 수 있다. 이를 해결하기 위해 SSL/TLS(보안 소켓 계층 및 전송 계층 보안) 프로토콜이 사용된다.
- 보안 소켓(SSL/TLS)란?
- SSL(Secure Sockets Layer)과 TLS(Transport Layer Security)는 데이터를 암호화하여 안전하게 전송할 수 있도록 하는 프로토콜이다. TLS는 SSL의 개선된 버전이며, 현재 SSL은 사용되지 않고 TLS가 표준으로 자리 잡았다.
- 보안 소켓이 필요한 이유
- 데이터 무결성 보장: 전송 중 데이터가 변조되지 않도록 보호한다.
- 기밀성 유지: 암호화를 통해 데이터가 유출되지 않도록 한다.
- 인증(Authentication): 서버와 클라이언트가 신뢰할 수 있는 상대방인지 확인할 수 있다.
- 보안 소켓 동작 방식
- 핸드셰이크 과정: 클라이언트와 서버가 서로 인증하고 암호화 키를 교환한다.
- 대칭키 암호화 사용: 실제 데이터 전송은 성능을 고려해 대칭키 암호화를 사용한다.
- 데이터 전송: 암호화된 데이터를 주고받으며, 변조 여부를 검증한다.
3. C++ 코드 예제: OpenSSL을 활용한 암호화된 소켓 통신
- C++에서 OpenSSL을 활용하여 TLS 기반의 보안 소켓을 구현하는 간단한 예제를 살펴보자
Server 쪽 사이드 Code
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
#include <arpa/inet.h>
void InitOpenSSL() {
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
SSL_CTX* CreateContext() {
SSL_CTX* ctx = SSL_CTX_new(TLS_server_method());
if (!ctx) {
std::cerr << "Failed to create SSL context" << std::endl;
exit(EXIT_FAILURE);
}
return ctx;
}
int main() {
InitOpenSSL();
SSL_CTX* ctx = CreateContext();
SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM);
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(4433);
addr.sin_addr.s_addr = INADDR_ANY;
bind(server_fd, (sockaddr*)&addr, sizeof(addr));
listen(server_fd, 5);
int client_fd = accept(server_fd, nullptr, nullptr);
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, client_fd);
SSL_accept(ssl);
char buffer[1024] = {0};
SSL_read(ssl, buffer, sizeof(buffer));
std::cout << "Received: " << buffer << std::endl;
SSL_shutdown(ssl);
SSL_free(ssl);
close(client_fd);
SSL_CTX_free(ctx);
return 0;
}
Client 쪽 Side Code
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
#include <arpa/inet.h>
int main() {
SSL_library_init();
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
SSL* ssl = SSL_new(ctx);
int sock = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(4433);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
connect(sock, (sockaddr*)&addr, sizeof(addr));
SSL_set_fd(ssl, sock);
SSL_connect(ssl);
const char* msg = "Hello, Secure Server!";
SSL_write(ssl, msg, strlen(msg));
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
close(sock);
return 0;
}
실무에서 고려해야 할 사항 및 발생할 수 있는 문제점
- 인증서 관리
- TLS 기반의 암호화 소켓을 사용할 때는 신뢰할 수 있는 인증서를 사용해야 합니다. 자체 서명된 인증서를 사용할 경우 클라이언트가 신뢰하지 않을 수 있으므로, 신뢰할 수 있는 인증 기관(CA)에서 인증서를 발급받는 것이 중요하다.
- 성능 문제
- 암호화된 통신은 일반적인 소켓 통신보다 오버헤드가 증가할 수 있다. 이를 해결하기 위해
- 세션 재사용을 활용하여 TLS 핸드셰이크 비용 절감
- 하드웨어 가속 (예: TLS 오프로드 기능) 활용
- 최신 TLS 버전 사용 (TLS 1.3은 이전 버전보다 성능이 향상됨)
- 암호화된 통신은 일반적인 소켓 통신보다 오버헤드가 증가할 수 있다. 이를 해결하기 위해
- 취약점 및 보안 패치
- 암호화 소켓을 사용할 때는 최신 보안 패치를 적용하는 것이 중요하다. 특히 TLS 1.0 및 TLS 1.1은 보안 취약점이 존재하므로 최신 TLS 1.2 또는 TLS 1.3을 사용해야 한다.
포스팅을 마치면서 ..
보안과 암호화된 소켓 통신은 안전한 네트워크 통신을 위해 필수적인 요소다. OpenSSL과 같은 라이브러리를 활용하면 비교적 쉽게 보안 소켓을 구현할 수 있으며, 실무에서는 인증서 관리와 성능 최적화까지 신경 써야 한다. 앞으로 네트워크 보안 강화를 위해 HTTPS 및 VPN 터널링 등의 개념도 추가로 다룰 예정이다. 부족하지만 같이 지식을 쌓는 시간을 많이 만들 수 있도록 노력하겠다.