HTTP(10) - HTTPS

김지승·2025년 7월 16일

CS

목록 보기
16/22

HTTP vs HTTPS: 보안의 차이

HTTP (HyperText Transfer Protocol)

HTTP는 웹에서 클라이언트와 서버 간의 데이터 전송을 위한 프로토콜입니다. 하지만 HTTP는 다음과 같은 보안 취약점을 가지고 있습니다:

HTTP의 한계:

  • 평문 전송: 모든 데이터가 암호화되지 않은 상태로 전송
  • 도청 가능: 네트워크 상에서 누구든 데이터를 볼 수 있음
  • 변조 위험: 중간자가 데이터를 수정할 수 있음
  • 신원 확인 불가: 서버의 진위를 확인할 수 없음
클라이언트 ←→ [평문 데이터] ←→ 서버
              ↑
          해커가 도청 가능

HTTPS (HTTP Secure)

HTTPS는 HTTP에 SSL/TLS 암호화 계층을 추가한 프로토콜입니다. 기본 포트는 443번을 사용합니다.

HTTPS의 장점:

  • 암호화: 모든 통신 데이터가 암호화됨
  • 무결성: 데이터 변조를 감지할 수 있음
  • 인증: 서버의 신원을 확인할 수 있음
  • 기밀성: 제3자가 통신 내용을 볼 수 없음
클라이언트 ←→ [암호화된 데이터] ←→ 서버
              ↑
          해커가 해독 불가능

주요 차이점 비교

구분HTTPHTTPS
보안없음SSL/TLS 암호화
포트80443
속도빠름상대적으로 느림 (암호화 오버헤드)
인증서불필요SSL/TLS 인증서 필요
SEO불리함유리함 (Google 순위 요소)
브라우저 표시"안전하지 않음"자물쇠 아이콘

TLS/SSL 개념과 발전사

SSL (Secure Sockets Layer)

SSL은 1994년 넷스케이프에서 개발한 암호화 프로토콜입니다. 현재는 보안 취약점으로 인해 사용되지 않습니다.

SSL 버전 히스토리:

  • SSL 1.0: 공개되지 않음 (보안 결함)
  • SSL 2.0: 1995년 (심각한 보안 취약점)
  • SSL 3.0: 1996년 (POODLE 공격에 취약)

TLS (Transport Layer Security)

TLS는 SSL의 후속 표준으로, IETF에서 관리하는 공개 표준입니다.

TLS 버전별 특징:

TLS 1.0 (1999년)

  • SSL 3.0의 업그레이드 버전
  • 현재는 보안상 권장되지 않음

TLS 1.1 (2006년)

  • CBC 공격 보호 강화
  • 현재는 레거시로 분류

TLS 1.2 (2008년)

  • SHA-256 해시 함수 지원
  • 현재 가장 널리 사용되는 버전
  • 강력한 암호화 스위트 지원

TLS 1.3 (2018년)

  • 핸드셰이크 단순화로 성능 향상
  • 더 강력한 보안 (레거시 암호화 방식 제거)
  • 0-RTT 재개를 통한 빠른 연결
// Node.js에서 TLS 버전 확인
const https = require('https');
const options = {
  hostname: 'example.com',
  port: 443,
  path: '/',
  method: 'GET',
  secureProtocol: 'TLSv1_3_method' // TLS 1.3 강제
};

HTTPS 동작 원리: TLS 핸드셰이크 과정

핸드셰이크 과정 개요

TLS 핸드셰이크는 클라이언트와 서버가 안전한 연결을 설정하기 위한 과정입니다. 이 과정에서 암호화 방식을 협상하고, 서버 인증을 수행하며, 세션 키를 교환합니다.

TLS 1.2 핸드셰이크 상세 과정

sequenceDiagram
    participant C as 클라이언트
    participant S as 서버
    
    Note over C,S: 1. 초기 협상
    C->>S: ClientHello (지원 TLS 버전, 암호화 스위트, 랜덤값)
    S->>C: ServerHello (선택된 TLS 버전, 암호화 스위트, 랜덤값)
    
    Note over C,S: 2. 서버 인증
    S->>C: Certificate (서버 인증서)
    S->>C: ServerKeyExchange (키 교환 정보)
    S->>C: ServerHelloDone (서버 메시지 완료)
    
    Note over C,S: 3. 클라이언트 키 교환
    C->>S: ClientKeyExchange (사전 마스터 시크릿)
    C->>S: ChangeCipherSpec (암호화 스위트 활성화)
    C->>S: Finished (핸드셰이크 완료 확인)
    
    Note over C,S: 4. 완료
    S->>C: ChangeCipherSpec (서버 암호화 활성화)
    S->>C: Finished (서버 핸드셰이크 완료)
    
    Note over C,S: 5. 암호화된 통신 시작
    C->>S: 암호화된 HTTP 요청
    S->>C: 암호화된 HTTP 응답

각 단계별 상세 설명

1. ClientHello

클라이언트가 서버에게 연결을 요청하며 다음 정보를 전송합니다:

ClientHello {
  version: TLS 1.2,
  random: [32바이트 랜덤값],
  cipher_suites: [
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    ...
  ],
  extensions: [
    server_name: "example.com",
    supported_groups: [secp256r1, secp384r1],
    ...
  ]
}

2. ServerHello

서버가 클라이언트의 요청에 응답하며 선택한 설정을 전송합니다:

ServerHello {
  version: TLS 1.2,
  random: [32바이트 랜덤값],
  cipher_suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  extensions: [...]
}

3. Certificate

서버가 자신의 SSL/TLS 인증서를 클라이언트에게 전송합니다. 클라이언트는 이 인증서를 검증하여 서버의 신원을 확인합니다.

4. Key Exchange

선택된 키 교환 알고리즘(ECDHE, RSA 등)에 따라 암호화 키를 안전하게 교환합니다.

5. Session Key 생성

클라이언트와 서버의 랜덤값, 그리고 사전 마스터 시크릿을 조합하여 실제 암호화에 사용할 세션 키를 생성합니다.

TLS 1.3의 개선된 핸드셰이크

TLS 1.3에서는 핸드셰이크 과정이 더욱 단순화되어 성능이 향상되었습니다:

sequenceDiagram
    participant C as 클라이언트
    participant S as 서버
    
    C->>S: ClientHello + KeyShare
    S->>C: ServerHello + KeyShare + Certificate + Finished
    C->>S: Finished
    
    Note over C,S: 즉시 암호화된 통신 가능 (1-RTT)

SSL/TLS 인증서 심층 분석

인증서의 구조와 내용

SSL/TLS 인증서는 X.509 표준을 따르며, 다음과 같은 정보를 포함합니다:

Certificate {
  Version: 3
  Serial Number: 12:34:56:78:9a:bc:de:f0
  Signature Algorithm: sha256WithRSAEncryption
  Issuer: CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
  Validity:
    Not Before: Jan  1 00:00:00 2024 GMT
    Not After : Apr  1 23:59:59 2024 GMT
  Subject: CN=example.com
  Subject Public Key Info:
    Public Key Algorithm: rsaEncryption
    RSA Public Key: (2048 bit)
  X509v3 extensions:
    X509v3 Subject Alternative Name:
      DNS:example.com, DNS:www.example.com
    X509v3 Key Usage:
      Digital Signature, Key Encipherment
  Signature: [디지털 서명]
}

인증서 종류

1. DV (Domain Validated) 인증서

  • 검증 수준: 도메인 소유권만 확인
  • 발급 시간: 수분~수시간
  • 용도: 개인 웹사이트, 블로그
  • 표시: 기본 자물쇠 아이콘
# Let's Encrypt로 DV 인증서 발급
certbot certonly --webroot -w /var/www/html -d example.com

2. OV (Organization Validated) 인증서

  • 검증 수준: 도메인 + 조직 정보 확인
  • 발급 시간: 1-3일
  • 용도: 기업 웹사이트
  • 표시: 인증서 정보에 조직명 포함

3. EV (Extended Validation) 인증서

  • 검증 수준: 엄격한 조직 및 법적 실체 확인
  • 발급 시간: 1-2주
  • 용도: 금융, 전자상거래 등 고신뢰 사이트
  • 표시: 브라우저 주소창에 조직명 표시

인증서 체인과 신뢰 구조

Root CA (자체 서명)
  ↓
Intermediate CA (Root CA가 서명)
  ↓
End Entity Certificate (Intermediate CA가 서명)

신뢰 체인 검증 과정

  1. End Entity 검증: 웹사이트 인증서 확인
  2. Intermediate CA 검증: 중간 CA 인증서 확인
  3. Root CA 검증: 브라우저 신뢰 저장소에서 루트 CA 확인
// Node.js에서 인증서 체인 확인
const https = require('https');
const { execSync } = require('child_process');

function checkCertChain(hostname) {
  try {
    const output = execSync(`openssl s_client -showcerts -connect ${hostname}:443 < /dev/null`);
    console.log('Certificate chain verified');
  } catch (error) {
    console.error('Certificate validation failed:', error.message);
  }
}

checkCertChain('example.com');

인증서 관리 실무

1. 인증서 발급 및 갱신

# Certbot을 이용한 Let's Encrypt 인증서 자동 갱신
# crontab 설정
0 12 * * * /usr/bin/certbot renew --quiet

2. 인증서 모니터링

// 인증서 만료일 확인 스크립트
const https = require('https');

function checkCertExpiry(hostname) {
  const options = {
    hostname: hostname,
    port: 443,
    method: 'GET',
    rejectUnauthorized: false
  };

  const req = https.request(options, (res) => {
    const cert = res.socket.getPeerCertificate();
    const expiryDate = new Date(cert.valid_to);
    const daysUntilExpiry = Math.ceil((expiryDate - new Date()) / (1000 * 60 * 60 * 24));
    
    console.log(`${hostname} 인증서 만료까지: ${daysUntilExpiry}`);
    
    if (daysUntilExpiry < 30) {
      console.warn('⚠️ 인증서 갱신이 필요합니다!');
    }
  });

  req.on('error', (error) => {
    console.error('Error:', error.message);
  });

  req.end();
}

checkCertExpiry('example.com');

3. NGINX SSL 설정 최적화

server {
    listen 443 ssl http2;
    server_name example.com;

    # 인증서 설정
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL 보안 설정
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # HSTS 설정
    add_header Strict-Transport-Security "max-age=63072000" always;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    # 성능 최적화
    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_session_tickets off;
}

인증서 보안 고려사항

1. 개인키 보호

# 개인키 파일 권한 설정
chmod 600 /etc/ssl/private/example.com.key
chown root:root /etc/ssl/private/example.com.key

# 개인키 암호화
openssl rsa -in example.com.key -des3 -out example.com.encrypted.key

2. Certificate Transparency (CT)

모든 공인 CA에서 발급하는 인증서는 CT 로그에 기록됩니다:

// CT 로그 조회 예시
async function checkCTLogs(domain) {
  const response = await fetch(`https://crt.sh/?q=${domain}&output=json`);
  const certificates = await response.json();
  
  certificates.forEach(cert => {
    console.log(`발급일: ${cert.not_before}, 만료일: ${cert.not_after}`);
    console.log(`CA: ${cert.issuer_name}`);
  });
}

3. HPKP (HTTP Public Key Pinning)

// 인증서 핀 생성
const crypto = require('crypto');

function generateSPKIFingerprint(cert) {
  const spki = cert.raw;
  const hash = crypto.createHash('sha256');
  hash.update(spki);
  return hash.digest('base64');
}

성능 최적화와 보안 강화

1. TLS 성능 최적화

Session Resumption

# TLS 세션 캐시 설정
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

OCSP Stapling

# OCSP 응답 캐싱으로 핸드셰이크 속도 향상
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;

2. 보안 헤더 설정

// Express.js 보안 헤더 설정
app.use((req, res, next) => {
  // HSTS
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  
  // CSP
  res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline'");
  
  // X-Frame-Options
  res.setHeader('X-Frame-Options', 'DENY');
  
  // X-Content-Type-Options
  res.setHeader('X-Content-Type-Options', 'nosniff');
  
  next();
});

3. 보안 테스트 도구

# SSL Labs 테스트 자동화
curl -s "https://api.ssllabs.com/api/v3/analyze?host=example.com" | jq '.grade'

# testssl.sh를 이용한 종합 테스트
./testssl.sh --fast --parallel example.com

결론

HTTPS는 현대 웹의 필수 요소가 되었습니다. TLS/SSL의 동작 원리를 이해하고 적절한 인증서를 선택하여 구현하는 것은 웹 개발자의 기본 역량입니다.

보안은 한 번 설정하고 끝나는 것이 아니라 지속적인 관리와 업데이트가 필요한 영역입니다. 인증서 갱신, 보안 패치, 새로운 취약점 대응 등을 통해 안전한 웹 환경을 유지해야 합니다.

앞으로는 양자 컴퓨팅 시대를 대비한 새로운 암호화 기술과 더욱 강화된 프라이버시 보호 기술들이 등장할 예정입니다. 이러한 변화에 발맞춰 지속적인 학습과 대응이 필요할 것입니다.

profile
디등

0개의 댓글