SSL Sertifika İzleme: Certificate Transparency Log Nedir ve Nasıl Kullanılır?

Bir sabah işe geldiniz ve güvenlik ekibinden acil bir mesaj var: “Domain’inize ait yeni bir SSL sertifikası düzenlenmiş, ama biz sipariş vermedik.” Bu senaryo kulağa paranoya gibi gelebilir, ancak gerçek dünyada bu tür olaylar düşündüğünüzden çok daha sık yaşanıyor. Phishing saldırıları, subdomain ele geçirme girişimleri veya yetkisiz sertifika düzenleme olayları, Certificate Transparency (CT) loglarını izlemediğiniz sürece fark etmeniz neredeyse imkansız olan tehditler arasında.

Certificate Transparency, 2013 yılında Google tarafından önerilen ve RFC 6962 ile standart hale gelen bir mekanizma. Temel fikir şu: tüm sertifika otoriteleri (CA) düzenledikleri her sertifikayı halka açık, denetlenebilir ve değiştirilemez log sunucularına kaydetmek zorunda. Bu loglar sayesinde domain sahipleri, kim tarafından hangi sertifikanın düzenlendiğini takip edebiliyor.

Certificate Transparency Nasıl Çalışır

CT sistemi üç ana bileşenden oluşuyor:

  • Log sunucuları: Merkle ağacı yapısını kullanan, append-only (sadece ekleme yapılabilen) veritabanları. Google, Cloudflare, DigiCert ve Sectigo gibi şirketler bu sunucuları işletiyor.
  • Monitor servisleri: Logları sürekli tarayan ve belirli domain’lere ait sertifikaları tespit eden sistemler.
  • Auditor servisleri: Log sunucularının dürüstlüğünü doğrulayan bileşenler.

Bir CA yeni sertifika düzenlediğinde şu süreç işliyor:

  1. CA, sertifikayı bir veya daha fazla CT log sunucusuna gönderiyor
  2. Log sunucusu “Signed Certificate Timestamp” (SCT) ile yanıt veriyor
  3. Bu SCT, sertifikanın kendisine ya da TLS handshake sürecine ekleniyor
  4. Tarayıcılar bu SCT’yi doğrulayarak sertifikanın log’a kaydedilip kaydedilmediğini kontrol ediyor

Chrome, 2018’den itibaren CT uyumluluğu olmayan sertifikalara güvenmemeye başladı. Bu tarihten sonra CT izleme hem güvenlik hem de operasyonel açıdan kritik bir hal aldı.

crt.sh ile Manuel İzleme

crt.sh, Comodo/Sectigo tarafından işletilen ücretsiz bir CT log arama motoru. Hızlı kontroller için ideal bir başlangıç noktası.

Curl ile basit bir domain sorgulama:

curl -s "https://crt.sh/?q=example.com&output=json" | 
  python3 -m json.tool | 
  grep -E '"name_value"|"issuer_name"|"not_before"'

Wildcard ve subdomain dahil tüm kayıtları çekmek için:

curl -s "https://crt.sh/?q=%25.example.com&output=json" | 
  python3 -c "
import json, sys
data = json.load(sys.stdin)
for cert in data:
    print(f"[{cert['not_before']}] {cert['name_value']} - {cert['issuer_name']}")
" | sort -u

Bu komut size son 90 günde düzenlenen tüm sertifikaları, hangi CA tarafından düzenlendiğini ve geçerlilik başlangıç tarihini gösteriyor. Düzenli olarak çalıştırıp çıktıyı bir önceki çalıştırmayla karşılaştırırsanız yeni sertifikaları tespit edebilirsiniz.

Otomatik İzleme Script’i

Manuel kontrolden daha iyisi, bu işi otomatize etmek. Aşağıdaki script, belirtilen domain’ler için CT loglarını sorgular ve yeni sertifika tespit ettiğinde e-posta ile bildirim gönderir.

#!/bin/bash

# cert_monitor.sh - CT Log izleme scripti
DOMAINS=("example.com" "company.net" "internal.example.com")
KNOWN_CERTS_DB="/var/lib/cert-monitor/known_certs.db"
MAIL_TO="[email protected]"
LOG_FILE="/var/log/cert-monitor.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

mkdir -p "$(dirname $KNOWN_CERTS_DB)"
touch "$KNOWN_CERTS_DB"

for DOMAIN in "${DOMAINS[@]}"; do
    log "Checking domain: $DOMAIN"
    
    CERTS=$(curl -s "https://crt.sh/?q=%25.${DOMAIN}&output=json" 
        --max-time 30 
        --retry 3 
        --retry-delay 5)
    
    if [ $? -ne 0 ] || [ -z "$CERTS" ]; then
        log "ERROR: Could not fetch CT logs for $DOMAIN"
        continue
    fi
    
    NEW_CERTS=$(echo "$CERTS" | python3 -c "
import json, sys
data = json.load(sys.stdin)
for cert in data:
    cert_id = str(cert.get('id', ''))
    name = cert.get('name_value', '').replace('n', ', ')
    issuer = cert.get('issuer_name', '')
    not_before = cert.get('not_before', '')
    print(f'{cert_id}|{name}|{issuer}|{not_before}')
" 2>/dev/null)
    
    while IFS='|' read -r cert_id name issuer not_before; do
        if ! grep -q "^${cert_id}$" "$KNOWN_CERTS_DB"; then
            echo "$cert_id" >> "$KNOWN_CERTS_DB"
            log "NEW CERT FOUND: $name (Issuer: $issuer, Date: $not_before)"
            
            echo "Yeni SSL sertifikasi tespit edildi!
Domain: $DOMAIN
Sertifika: $name
Duzenleyen CA: $issuer
Tarih: $not_before
crt.sh link: https://crt.sh/?id=$cert_id" | 
            mail -s "[CERT-MONITOR] Yeni sertifika: $DOMAIN" "$MAIL_TO"
        fi
    done <<< "$NEW_CERTS"
done

log "Monitoring cycle completed"

Bu scripti cron’a ekleyerek her saat çalıştırabilirsiniz:

# Crontab'a ekle
0 * * * * /usr/local/bin/cert_monitor.sh >> /var/log/cert-monitor.log 2>&1

Certstream ile Gerçek Zamanlı İzleme

crt.sh polling-based bir yaklaşım sunuyor, yani periyodik olarak sorgulama yapıyorsunuz. Daha gerçek zamanlı bir çözüm için Certstream kullanabilirsiniz. Certstream, tüm CT loglarını anlık olarak akış halinde sunan bir WebSocket servisi.

pip3 install certstream

Python ile basit bir izleme scripti:

#!/usr/bin/env python3
# certstream_monitor.py

import certstream
import re
import json
import smtplib
from email.mime.text import MIMEText
from datetime import datetime

WATCH_DOMAINS = [
    "example.com",
    "company.net",
    "mybank.com"
]

def send_alert(domain, cert_data):
    msg = MIMEText(f"""
Zaman: {datetime.now().isoformat()}
Tespit edilen domain: {domain}
CN: {cert_data.get('leaf_cert', {}).get('subject', {}).get('CN', 'N/A')}
SAN'lar: {', '.join(cert_data.get('leaf_cert', {}).get('all_domains', []))}
Duzenleyen: {cert_data.get('leaf_cert', {}).get('issuer', {}).get('O', 'N/A')}
""")
    msg['Subject'] = f'[ALERT] Yeni CT log girisi: {domain}'
    msg['From'] = '[email protected]'
    msg['To'] = '[email protected]'
    
    with smtplib.SMTP('localhost') as s:
        s.send_message(msg)

def callback(message, context):
    if message['message_type'] == "heartbeat":
        return
    
    if message['message_type'] == "certificate_update":
        all_domains = message['data']['leaf_cert']['all_domains']
        
        for domain in all_domains:
            for watched in WATCH_DOMAINS:
                # Wildcard ve subdomain kontrolu
                if watched in domain or domain.endswith(f'.{watched}'):
                    print(f"[{datetime.now()}] HIT: {domain} (izlenen: {watched})")
                    send_alert(domain, message['data'])

certstream.listen_for_events(callback, url='wss://certstream.calidog.io/')

Bu scripti systemd servisi olarak çalıştırmak için:

# /etc/systemd/system/certstream-monitor.service
[Unit]
Description=Certificate Transparency Stream Monitor
After=network.target

[Service]
Type=simple
User=certmonitor
ExecStart=/usr/bin/python3 /opt/cert-monitor/certstream_monitor.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now certstream-monitor
journalctl -u certstream-monitor -f

Mevcut Sertifikaların Detaylı Analizi

İzlemenin yanı sıra, mevcut sertifikalarınızın detaylarını düzenli olarak analiz etmek de önemli. OpenSSL ile bir domain’in güncel sertifikasını kontrol etmek:

#!/bin/bash
# check_cert_details.sh

DOMAIN=$1
PORT=${2:-443}

echo "=== $DOMAIN:$PORT sertifika detaylari ==="

# Sertifika bilgilerini cek
CERT_INFO=$(echo | openssl s_client 
    -connect "${DOMAIN}:${PORT}" 
    -servername "$DOMAIN" 
    2>/dev/null | openssl x509 -noout 
    -subject 
    -issuer 
    -dates 
    -fingerprint 
    -ext subjectAltName)

echo "$CERT_INFO"

# SCT kontrolu - CT log'a kayitli mi?
echo ""
echo "=== SCT Kontrolu ==="
echo | openssl s_client 
    -connect "${DOMAIN}:${PORT}" 
    -servername "$DOMAIN" 
    2>/dev/null | openssl x509 -noout 
    -ext ctPoisonOrSCT 2>/dev/null || echo "SCT bilgisi TLS handshake'te kontrol edin"

# Kac gun kaldi?
EXPIRY=$(echo | openssl s_client 
    -connect "${DOMAIN}:${PORT}" 
    -servername "$DOMAIN" 
    2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

if [ -n "$EXPIRY" ]; then
    EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$EXPIRY" +%s)
    NOW_EPOCH=$(date +%s)
    DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
    echo ""
    echo "Kalan sure: $DAYS_LEFT gun ($EXPIRY)"
    
    if [ "$DAYS_LEFT" -lt 30 ]; then
        echo "UYARI: Sertifika 30 gun icinde sona eriyor!"
    fi
fi

Prometheus ile Metrik Toplama

Kurumsal ortamlarda CT izlemeyi Prometheus/Grafana stack’ine entegre etmek çok daha fazla görünürlük sağlıyor. Basit bir custom exporter:

#!/usr/bin/env python3
# cert_exporter.py - Prometheus custom exporter

from prometheus_client import start_http_server, Gauge
import ssl
import socket
import time
import datetime

CERT_EXPIRY_DAYS = Gauge(
    'ssl_certificate_expiry_days',
    'SSL sertifikasinin son gecelilik tarihe kalan gun sayisi',
    ['domain', 'issuer']
)

CERT_VALID = Gauge(
    'ssl_certificate_valid',
    'SSL sertifikasi gecerli mi (1=gecerli, 0=gecersiz)',
    ['domain']
)

DOMAINS_TO_MONITOR = [
    ("example.com", 443),
    ("api.example.com", 443),
    ("mail.example.com", 443),
]

def check_certificate(domain, port):
    try:
        ctx = ssl.create_default_context()
        with socket.create_connection((domain, port), timeout=10) as sock:
            with ctx.wrap_socket(sock, server_hostname=domain) as ssock:
                cert = ssock.getpeercert()
                
        not_after = cert['notAfter']
        expiry_date = datetime.datetime.strptime(
            not_after, '%b %d %H:%M:%S %Y %Z'
        )
        days_remaining = (expiry_date - datetime.datetime.utcnow()).days
        
        issuer = dict(x[0] for x in cert['issuer'])
        issuer_cn = issuer.get('commonName', 'Unknown')
        
        CERT_EXPIRY_DAYS.labels(domain=domain, issuer=issuer_cn).set(days_remaining)
        CERT_VALID.labels(domain=domain).set(1)
        
        print(f"{domain}: {days_remaining} gun kaldi (Issuer: {issuer_cn})")
        
    except Exception as e:
        print(f"ERROR {domain}: {e}")
        CERT_VALID.labels(domain=domain).set(0)
        CERT_EXPIRY_DAYS.labels(domain=domain, issuer="error").set(-1)

if __name__ == '__main__':
    start_http_server(9115)
    print("Exporter baslatildi: :9115/metrics")
    
    while True:
        for domain, port in DOMAINS_TO_MONITOR:
            check_certificate(domain, port)
        time.sleep(300)  # Her 5 dakikada bir kontrol

Prometheus scrape konfigürasyonu:

# prometheus.yml'e eklenecek bolum
scrape_configs:
  - job_name: 'ssl_certificates'
    static_configs:
      - targets: ['localhost:9115']
    scrape_interval: 5m

Gerçek Dünya Senaryosu: Phishing Tespiti

Diyelim ki “mybank.com” domain’ini işletiyorsunuz. Saldırganlar kullanıcıları kandırmak için “mybank-secure.com” veya “login.mybank.com.evil.net” gibi domainler için sertifika düzenleyebilir. CT loglarını izleyerek bu tür domainleri tespit edebilirsiniz.

Benzer domain tespiti için fuzzy matching kullanan bir script:

#!/usr/bin/env python3
# phishing_detector.py

import requests
import json
import re
from difflib import SequenceMatcher

TARGET_BRAND = "mybank"
SUSPICIOUS_KEYWORDS = ["login", "secure", "account", "verify", "update", "banking"]
KNOWN_LEGIT_DOMAINS = {"mybank.com", "mybank.net", "api.mybank.com"}

def similarity_score(a, b):
    return SequenceMatcher(None, a, b).ratio()

def is_suspicious(domain):
    domain_lower = domain.lower()
    
    # Brand adi geciyorsa ve bilinen domain degilse
    if TARGET_BRAND in domain_lower and domain_lower not in KNOWN_LEGIT_DOMAINS:
        # Subdomain kontrolu - kendi domainimizin subdomaini mi?
        for legit in KNOWN_LEGIT_DOMAINS:
            if domain_lower.endswith(f".{legit}"):
                return False  # Kendi subdomainimiz
        
        return True
    
    # Phishing keyword kombinasyonu
    keyword_count = sum(1 for kw in SUSPICIOUS_KEYWORDS if kw in domain_lower)
    if keyword_count >= 2 and TARGET_BRAND in domain_lower:
        return True
    
    return False

def check_ct_logs(domain_query):
    url = f"https://crt.sh/?q=%25{domain_query}%25&output=json"
    try:
        r = requests.get(url, timeout=30)
        certs = r.json()
        
        suspicious = []
        for cert in certs:
            domains = cert.get('name_value', '').split('n')
            for d in domains:
                d = d.strip().lstrip('*.')
                if is_suspicious(d):
                    suspicious.append({
                        'domain': d,
                        'issuer': cert.get('issuer_name', ''),
                        'date': cert.get('not_before', ''),
                        'cert_id': cert.get('id', '')
                    })
        
        return suspicious
    except Exception as e:
        print(f"Hata: {e}")
        return []

results = check_ct_logs(TARGET_BRAND)
if results:
    print(f"DIKKAT: {len(results)} suphehi domain tespit edildi!")
    for r in results:
        print(f"  - {r['domain']}")
        print(f"    Duzenleyen: {r['issuer']}")
        print(f"    Tarih: {r['date']}")
        print(f"    Link: https://crt.sh/?id={r['cert_id']}")
else:
    print("Suphehi domain tespit edilmedi.")

CAA DNS Kaydı ile CT İzlemeyi Tamamlamak

CT izleme reaktif bir yaklaşım. Proaktif koruma için CAA (Certification Authority Authorization) DNS kayıtlarını da mutlaka yapılandırın. CAA, hangi CA’ların domain’iniz için sertifika düzenleyebileceğini belirler.

# Mevcut CAA kayitlarini kontrol et
dig CAA example.com

# CAA kaydi ornegi - zone dosyasina eklenecek
# example.com.  IN  CAA  0 issue "letsencrypt.org"
# example.com.  IN  CAA  0 issue "digicert.com"
# example.com.  IN  CAA  0 issuewild ";"  (wildcard yasak)
# example.com.  IN  CAA  0 iodef "mailto:[email protected]"

# CAA kaydi dogrulama
dig +short CAA example.com
curl -s "https://crt.sh/?caid=16418&output=json" | python3 -m json.tool | head -50

CAA ve CT birlikte kullanıldığında güçlü bir savunma katmanı oluşturuyorlar. CAA yetkisiz sertifika düzenlenmesini önlüyor, CT ise eğer bir şekilde düzenlenirse bunu tespit etmenizi sağlıyor.

İzleme Araçları Karşılaştırması

Hangi aracı kullanacağınız ortamınıza ve ihtiyaçlarınıza bağlı:

  • crt.sh: Ücretsiz, API mevcut, basit polling için ideal. Küçük ve orta ölçekli ortamlar için başlangıç noktası.
  • Certstream: Gerçek zamanlı WebSocket akışı, açık kaynak, yüksek hacimli izleme için uygun.
  • Facebook CT Monitor: Meta’nın sunduğu ücretsiz e-posta bildirim servisi, teknik olmayan ekipler için pratik.
  • Cert Spotter (SSLMate): Ücretli ama çok kapsamlı API ve webhook desteği, kurumsal kullanım için güçlü.
  • Hardenize / Detectify: Tam kapsamlı attack surface monitoring platformları, CT izleme dahil.

Uyarı Eşikleri ve False Positive Yönetimi

CT izleme sistemleri zamanla çok fazla bildirim üretmeye başlayabilir. False positive’leri azaltmak için şu yaklaşımları uygulayın:

  • Kendi CA’nız veya bilinen CA’lar (Let’s Encrypt, DigiCert vb.) tarafından düzenlenen sertifikaları whitelist’e alın
  • Bilinen subdomain’lerinizi bir veritabanında tutun ve sadece yeni subdomain’ler için uyarı üretin
  • Sertifika düzenleme onaylarını ticketing sisteminizle (Jira, ServiceNow) entegre edin; onaylı talepler otomatik olarak karşılaştırma listesine eklensin
  • Wildcard sertifikaları özel olarak takip edin; bu sertifikalar tüm subdomainleri kapsadığı için risk profili farklı

Sonuç

Certificate Transparency log izleme, modern SSL/TLS güvenliğinin vazgeçilmez bir parçası haline geldi. Sadece güvenlik ekipleri için değil, operasyon ve DevOps ekipleri için de kritik bir monitoring katmanı oluşturuyor. Yetkisiz sertifika tespitinden subdomain takeover önlemeye, phishing altyapısı tespitinden uyumluluk denetimine kadar geniş bir kullanım alanı sunuyor.

Pratik önerim şu: hemen bu gece crt.sh’e girin ve domain’lerinizi sorgulayın. Şu ana kadar kaç sertifika düzenlenmiş, hepsinden haberdar mısınız? Çoğu zaman bu ilk sorgulama bile sürprizler ortaya çıkartıyor. Sonra basit bir cron job ile otomatik izlemeye geçin, zamanla Certstream veya Prometheus tabanlı daha kapsamlı bir çözüme evrilebilirsiniz.

CAA kayıtlarını yapılandırmak, CT izlemeyi otomatize etmek ve bildirimleri doğru kişilere iletmek için birkaç saatinizi ayırmanız yeterli. Bu yatırım, olası bir sertifika tabanlı saldırıyı saatler yerine dakikalar içinde fark etmenizi sağlar. Sysadmin olarak bunu geciktirmenin hiçbir mazereti yok.

Yorum yapın