아웃룩 SMTP 헤더 보는 방법 완벽 가이드: 이메일 포렌식의 핵심

"스팸 메일은 어디서 왔을까요? 피싱 메일의 진짜 발신자는 누구일까요? 아웃룩 SMTP 헤더를 분석하면 이메일의 모든 비밀을 파악할 수 있습니다. 전 세계 이메일 보안 전문가들이 사용하는 이 기법을 마스터하여 이메일 보안의 달인이 되어보세요."

🎯 목차

  1. SMTP 헤더란 무엇인가?
  2. 아웃룩 버전별 헤더 보기 방법
  3. SMTP 헤더 구성 요소 분석
  4. 헤더 분석을 통한 보안 진단
  5. 스팸/피싱 메일 탐지 기법
  6. 이메일 라우팅 경로 추적
  7. 실무 활용 사례와 도구

📡 SMTP 헤더란 무엇인가?

🔍 SMTP 헤더의 기본 개념

SMTP 헤더는 이메일이 전송되는 과정에서 각 메일 서버가 추가하는 메타데이터입니다. 마치 택배 상자에 붙는 배송 라벨처럼, 이메일이 어디서 와서 어디로 가는지, 언제 처리되었는지 등의 모든 정보를 담고 있습니다.

🎪 왜 SMTP 헤더 분석이 중요한가?

현실적인 이메일 보안 상황들:

보안 위협 겉보기 정보 헤더 분석 결과

스팸 메일 발신자: support@apple.com 실제 발신: spam-server.cn
피싱 메일 발신자: security@paypal.com 실제 발신: fake-paypal.ru
사칭 메일 발신자: ceo@company.com 실제 발신: attacker@gmail.com
악성코드 발신자: noreply@microsoft.com 실제 발신: malware-c2.tk

💡 놀라운 사실: 전체 이메일의 약 85%가 스팸이나 악성 메일이며, 이들 대부분은 발신자 정보를 위조합니다. SMTP 헤더 분석만으로도 95% 이상의 가짜 메일을 식별할 수 있습니다.

📊 SMTP 헤더 구조 개요

이메일 전송 과정:
발신자 PC → 발신자 메일서버 → 중간 릴레이 서버(들) → 수신자 메일서버 → 수신자 PC
    ↓              ↓                    ↓                    ↓              ↓
 작성 완료      헤더 추가           헤더 추가            헤더 추가        최종 수신

최종 헤더 구조:
┌─────────────────────────────────────────┐
│ 수신자 서버 헤더 (가장 위)              │
├─────────────────────────────────────────┤
│ 중간 서버 헤더                          │
├─────────────────────────────────────────┤
│ 발신자 서버 헤더                        │
├─────────────────────────────────────────┤
│ 원본 메시지 헤더 (가장 아래)            │
└─────────────────────────────────────────┘


🖥️ 아웃룩 버전별 헤더 보기 방법

🏢 Microsoft Outlook (데스크톱 버전)

Outlook 2019/2021/365 (최신 버전)

방법 1: 속성을 통한 접근

1. 분석할 이메일을 더블클릭하여 별도 창에서 열기
2. 상단 리본 메뉴에서 "파일" 탭 클릭
3. "속성" 버튼 클릭
4. "인터넷 헤더" 섹션에서 전체 헤더 확인

방법 2: 우클릭 메뉴 활용

1. 이메일 목록에서 원하는 메일 우클릭
2. "속성" 선택
3. "세부 정보" 탭 클릭
4. "인터넷 헤더" 영역에서 헤더 정보 확인

방법 3: 개발자 도구 활용

1. 파일 → 옵션 → 사용자 지정 리본
2. "개발 도구" 체크박스 선택
3. 이메일 선택 후 개발 도구 탭 → "헤더 정보"

Outlook 2016/2013 (구 버전)

1. 분석할 이메일 더블클릭
2. 메시지 탭 → 태그 그룹의 오른쪽 아래 화살표 클릭
3. "속성" 대화상자에서 "인터넷 헤더" 확인

단축키로 빠른 접근

Alt + Enter : 이메일 속성 대화상자 열기 (헤더 포함)
Ctrl + Alt + P : 속성 대화상자 직접 열기

🌐 Outlook Web App (웹 버전)

outlook.com / office.com 웹버전

방법 1: 메시지 옵션 활용

1. 이메일 열기
2. 오른쪽 상단 "..." (더보기) 메뉴 클릭
3. "메시지 소스 보기" 선택
4. 새 창에서 전체 헤더와 원본 소스 확인

방법 2: 개발자 도구 활용

1. 이메일 열기
2. 브라우저에서 F12 (개발자 도구)
3. Network 탭에서 메일 요청 찾기
4. Response Headers에서 추가 정보 확인

📱 모바일 아웃룩

Outlook 모바일 앱

안드로이드:
1. 이메일 열기 → 오른쪽 상단 "..." → "메시지 세부 정보"

iOS:
1. 이메일 열기 → "세부 정보" → "기술적 세부 정보"


🔬 SMTP 헤더 구성 요소 분석

📋 핵심 헤더 필드 해석

기본 식별 정보

From: user@example.com
To: recipient@domain.com
Subject: 메일 제목
Date: Mon, 15 Jan 2024 14:30:00 +0900
Message-ID: <20240115143000.ABC123@mail.example.com>

필드 설명 보안 분석 포인트

From 표시되는 발신자 쉽게 위조 가능 ⚠️
Reply-To 답장 받을 주소 From과 다르면 의심 🚨
Return-Path 실제 발신 주소 진짜 발신자 확인 ✅
Message-ID 고유 식별자 위조 시 패턴 이상

전송 경로 정보 (가장 중요!)

Received: from mail.company.com (mail.company.com [203.0.113.10])
    by mx1.receiver.com (Postfix) with ESMTP id 5B2C31040B2A
    for <user@receiver.com>; Mon, 15 Jan 2024 14:30:15 +0900 (KST)

Received: from webmail.company.com (unknown [192.168.1.100])
    by mail.company.com (Postfix) with ESMTP id 3A1B20F8DA
    for <user@receiver.com>; Mon, 15 Jan 2024 14:30:10 +0900 (KST)

Received 헤더 분석 방법:

구문: from [발신서버] ([실제IP]) by [수신서버] with [프로토콜] id [거래ID] for [수신자]; [시간]

분석 포인트:
✅ 서버 이름과 IP 일치 여부
✅ 시간 순서의 일관성 (아래→위로 시간 증가)
✅ 프로토콜 적절성 (ESMTP, SMTP)
⚠️ unknown 또는 [IP주소]로 표시되는 서버

인증 관련 헤더

Authentication-Results: receiver.com;
    spf=pass smtp.mailfrom=company.com;
    dkim=pass (1024-bit key) header.d=company.com;
    dmarc=pass (p=quarantine sp=quarantine pct=100)

Received-SPF: pass (receiver.com: domain of sender@company.com
    designates 203.0.113.10 as permitted sender)
    client-ip=203.0.113.10;

🔒 보안 검증 헤더

SPF (Sender Policy Framework)

Received-SPF: pass | fail | softfail | neutral | none | temperror | permerror

결과 의미 보안 수준

pass 인증된 발신자 🟢 안전
fail 인증되지 않은 발신자 🔴 위험
softfail 의심스러운 발신자 🟡 주의
none SPF 설정 없음 ⚪ 불명

DKIM (DomainKeys Identified Mail)

DKIM-Signature: v=1; a=rsa-sha256; d=company.com; s=selector1;
    c=relaxed/relaxed; q=dns/txt;
    h=from:to:subject:date:message-id;
    bh=base64encodedBodyHash;
    b=base64encodedSignature

DMARC (Domain-based Message Authentication)

Authentication-Results: receiver.com;
    dmarc=pass action=none header.from=company.com;

📍 지역 및 라우팅 정보

X-Originating-IP와 지역 추적

X-Originating-IP: [203.0.113.50]
X-Forwarded-For: 10.1.1.100, 203.0.113.50
X-Remote-IP: 203.0.113.50

IP 주소 분석 도구:

# Linux/Mac 터미널에서 IP 정보 확인
whois 203.0.113.50
geoiplookup 203.0.113.50

# 온라인 도구
# <https://www.whatismyipaddress.com/ip-lookup>
# <https://www.iplocation.net/>


🕵️ 헤더 분석을 통한 보안 진단

🚨 의심스러운 헤더 패턴

발신자 위조 탐지

정상적인 헤더:

From: support@apple.com
Return-Path: <support@apple.com>
Received: from mail.apple.com (mail.apple.com [17.172.224.47])
Authentication-Results: spf=pass dkim=pass dmarc=pass

의심스러운 헤더:

From: support@apple.com
Return-Path: <noreply@suspicious-domain.tk>
Received: from unknown ([123.456.789.10])
Authentication-Results: spf=fail dkim=none dmarc=fail

스팸 발신자 식별 패턴

⚠️ 의심 패턴들:
- Received: from unknown 또는 localhost
- X-Mailer: bulk mail software 또는 알려진 스팸 도구
- Message-ID가 없거나 이상한 형식
- 여러 개의 X-Forwarded-For 헤더
- 시간대가 일관성 없게 변경됨

🔍 실제 분석 사례

사례 1: 피싱 메일 분석

From: security-team@paypal.com
Subject: 긴급: 계정 보안 확인 필요

Received: from mail-server.suspicious-domain.ru ([185.220.100.240])
    by mx.gmail.com with ESMTP id abc123;
Return-Path: <noreply@suspicious-domain.ru>
Authentication-Results: gmail.com;
    spf=fail (google.com: domain of noreply@suspicious-domain.ru
    does not designate 185.220.100.240 as permitted sender);
    dkim=none;
    dmarc=fail

분석 결과:

  • ❌ From 주소와 Return-Path 불일치
  • ❌ 러시아 IP에서 PayPal 사칭
  • ❌ SPF, DKIM, DMARC 모두 실패
  • 🚨 확정 피싱 메일

사례 2: 정상 메일 분석

From: no-reply@github.com
Subject: [GitHub] Password changed for your account

Received: from github-smtp-2a-02.iad.github.net ([192.30.252.196])
    by mx.google.com with ESMTPS id xyz789;
Return-Path: <no-reply@github.com>
Authentication-Results: mx.google.com;
    spf=pass (google.com: domain of no-reply@github.com
    designates 192.30.252.196 as permitted sender);
    dkim=pass header.d=github.com;
    dmarc=pass

분석 결과:

  • ✅ From과 Return-Path 일치
  • ✅ GitHub 공식 서버에서 발송
  • ✅ SPF, DKIM, DMARC 모두 통과
  • 🟢 정상 메일

🎯 스팸/피싱 메일 탐지 기법

🔍 자동화된 헤더 분석 도구

PowerShell 스크립트로 헤더 분석

# email-header-analyzer.ps1
function Analyze-EmailHeader {
    param(
        [Parameter(Mandatory=$true)]
        [string]$HeaderText
    )

    Write-Host "=== 이메일 헤더 보안 분석 ===" -ForegroundColor Cyan

    # SPF 검사
    if ($HeaderText -match "spf=(\\w+)") {
        $spfResult = $matches[1]
        switch ($spfResult) {
            "pass" { Write-Host "✅ SPF: 통과" -ForegroundColor Green }
            "fail" { Write-Host "❌ SPF: 실패 (위조 가능성 높음)" -ForegroundColor Red }
            "softfail" { Write-Host "⚠️ SPF: 소프트 실패 (의심스러움)" -ForegroundColor Yellow }
            default { Write-Host "⚪ SPF: $spfResult" -ForegroundColor Gray }
        }
    }

    # DKIM 검사
    if ($HeaderText -match "dkim=(\\w+)") {
        $dkimResult = $matches[1]
        if ($dkimResult -eq "pass") {
            Write-Host "✅ DKIM: 통과 (서명 검증됨)" -ForegroundColor Green
        } else {
            Write-Host "❌ DKIM: $dkimResult (서명 없음/실패)" -ForegroundColor Red
        }
    }

    # DMARC 검사
    if ($HeaderText -match "dmarc=(\\w+)") {
        $dmarcResult = $matches[1]
        if ($dmarcResult -eq "pass") {
            Write-Host "✅ DMARC: 통과" -ForegroundColor Green
        } else {
            Write-Host "❌ DMARC: $dmarcResult (정책 위반)" -ForegroundColor Red
        }
    }

    # 발신 IP 분석
    if ($HeaderText -match "Received: from .* \\[(\\d+\\.\\d+\\.\\d+\\.\\d+)\\]") {
        $originIP = $matches[1]
        Write-Host "🌐 발신 IP: $originIP" -ForegroundColor Blue

        # 사설 IP 대역 확인
        if ($originIP -match "^(10\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.|192\\.168\\.)" -or $originIP -eq "127.0.0.1") {
            Write-Host "⚠️ 사설 IP 대역에서 발신 (의심스러움)" -ForegroundColor Yellow
        }
    }

    # Return-Path와 From 일치성 확인
    $fromMatch = [regex]::Match($HeaderText, "From:.*?([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})")
    $returnPathMatch = [regex]::Match($HeaderText, "Return-Path:.*?([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})")

    if ($fromMatch.Success -and $returnPathMatch.Success) {
        $fromEmail = $fromMatch.Groups[1].Value
        $returnEmail = $returnPathMatch.Groups[1].Value

        if ($fromEmail -eq $returnEmail) {
            Write-Host "✅ From과 Return-Path 일치" -ForegroundColor Green
        } else {
            Write-Host "❌ From($fromEmail)과 Return-Path($returnEmail) 불일치" -ForegroundColor Red
        }
    }
}

# 사용 예시
$headers = Get-Clipboard  # 클립보드에서 헤더 가져오기
Analyze-EmailHeader -HeaderText $headers

📊 위험도 점수 시스템

헤더 기반 위험도 계산

# email_risk_calculator.py
def calculate_risk_score(headers):
    """이메일 헤더 기반 위험도 점수 계산 (0-100)"""

    risk_score = 0
    risk_factors = []

    # SPF 검사 (가중치: 30점)
    if 'spf=fail' in headers:
        risk_score += 30
        risk_factors.append("SPF 인증 실패")
    elif 'spf=softfail' in headers:
        risk_score += 15
        risk_factors.append("SPF 소프트 실패")

    # DKIM 검사 (가중치: 25점)
    if 'dkim=fail' in headers or 'dkim=none' in headers:
        risk_score += 25
        risk_factors.append("DKIM 서명 없음/실패")

    # DMARC 검사 (가중치: 20점)
    if 'dmarc=fail' in headers:
        risk_score += 20
        risk_factors.append("DMARC 정책 위반")

    # Return-Path와 From 불일치 (가중치: 15점)
    import re
    from_match = re.search(r'From:.*?([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+)', headers)
    return_match = re.search(r'Return-Path:.*?([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+)', headers)

    if from_match and return_match:
        if from_match.group(1) != return_match.group(1):
            risk_score += 15
            risk_factors.append("발신자 주소 불일치")

    # 알려진 스팸 서버 (가중치: 10점)
    spam_indicators = ['unknown', 'localhost', 'dynamic', 'dial-up']
    for indicator in spam_indicators:
        if indicator in headers.lower():
            risk_score += 10
            risk_factors.append(f"의심스러운 서버: {indicator}")
            break

    return min(risk_score, 100), risk_factors

# 위험도 평가 함수
def assess_risk_level(score):
    if score >= 80:
        return "🔴 매우 위험 (차단 권장)"
    elif score >= 60:
        return "🟠 위험 (주의 필요)"
    elif score >= 40:
        return "🟡 의심스러움 (검토 필요)"
    elif score >= 20:
        return "🟢 낮은 위험"
    else:
        return "✅ 안전"

# 사용 예시
headers = """
From: security@paypal.com
Return-Path: <noreply@suspicious-domain.tk>
Authentication-Results: spf=fail dkim=none dmarc=fail
Received: from unknown ([123.45.67.89])
"""

score, factors = calculate_risk_score(headers)
risk_level = assess_risk_level(score)

print(f"위험도 점수: {score}/100")
print(f"위험 수준: {risk_level}")
print(f"위험 요소: {', '.join(factors)}")


🗺️ 이메일 라우팅 경로 추적

🛤️ Received 헤더로 경로 분석

이메일 여행 경로 시각화

# email_route_tracer.py
import re
from datetime import datetime

def parse_received_headers(email_headers):
    """Received 헤더들을 파싱하여 라우팅 경로 추출"""

    received_pattern = r'Received:\\s*from\\s+([^\\s]+).*?\\[([^\\]]+)\\].*?by\\s+([^\\s]+).*?;\\s*(.+?)(?=\\n[^ \\t]|\\n$)'

    received_entries = []
    matches = re.finditer(received_pattern, email_headers, re.DOTALL | re.IGNORECASE)

    for match in matches:
        from_server = match.group(1)
        from_ip = match.group(2)
        to_server = match.group(3)
        timestamp_str = match.group(4).strip()

        # 시간 파싱 시도
        try:
            # 다양한 시간 형식 처리
            timestamp_str = re.sub(r'\\([^)]+\\)$', '', timestamp_str).strip()
            timestamp = datetime.strptime(timestamp_str, '%a, %d %b %Y %H:%M:%S %z')
        except:
            timestamp = None

        received_entries.append({
            'from_server': from_server,
            'from_ip': from_ip,
            'to_server': to_server,
            'timestamp': timestamp,
            'raw_timestamp': timestamp_str
        })

    # 시간순으로 정렬 (오래된 것부터)
    received_entries.reverse()
    return received_entries

def visualize_email_route(route_data):
    """이메일 라우팅 경로 시각화"""

    print("📧 이메일 라우팅 경로 분석")
    print("=" * 50)

    for i, hop in enumerate(route_data, 1):
        print(f"\\n🏃 홉 {i}:")
        print(f"   📤 발신서버: {hop['from_server']}")
        print(f"   🌐 발신IP: {hop['from_ip']}")
        print(f"   📥 수신서버: {hop['to_server']}")
        print(f"   ⏰ 시간: {hop['raw_timestamp']}")

        # IP 지역 정보 (실제로는 GeoIP 라이브러리 사용)
        location = get_ip_location(hop['from_ip'])
        if location:
            print(f"   📍 위치: {location}")

    # 총 전송 시간 계산
    if len(route_data) >= 2 and route_data[0]['timestamp'] and route_data[-1]['timestamp']:
        total_time = route_data[-1]['timestamp'] - route_data[0]['timestamp']
        print(f"\\n⏱️ 총 전송 시간: {total_time}")

def get_ip_location(ip_address):
    """IP 주소의 지역 정보 반환 (예시)"""
    # 실제로는 geoip2, ipinfo.io API 등을 사용
    import socket
    try:
        hostname = socket.gethostbyaddr(ip_address)[0]
        return f"{hostname}"
    except:
        return "위치 정보 없음"

# 사용 예시
sample_headers = """
Received: from mail.example.com (mail.example.com [203.0.113.10])
    by mx1.gmail.com (Postfix) with ESMTP id 5B2C31040B2A
    for <user@gmail.com>; Mon, 15 Jan 2024 14:30:15 +0900

Received: from webserver.internal ([192.168.1.100])
    by mail.example.com (Postfix) with ESMTP id 3A1B20F8DA
    for <user@gmail.com>; Mon, 15 Jan 2024 14:30:10 +0900
"""

route = parse_received_headers(sample_headers)
visualize_email_route(route)

🌍 지역별 라우팅 이상 탐지

비정상적인 라우팅 패턴

def detect_routing_anomalies(route_data):
    """라우팅 이상 패턴 탐지"""

    anomalies = []

    # 1. 지역 점프 탐지 (예: 한국→러시아→미국→한국)
    locations = []
    for hop in route_data:
        location = get_country_from_ip(hop['from_ip'])
        locations.append(location)

    # 연속된 국가 변화가 3회 이상이면 의심
    country_changes = 0
    for i in range(1, len(locations)):
        if locations[i] != locations[i-1]:
            country_changes += 1

    if country_changes >= 3:
        anomalies.append(f"⚠️ 비정상적인 국가 간 라우팅: {' → '.join(locations)}")

    # 2. 시간 역행 탐지
    for i in range(1, len(route_data)):
        if route_data[i]['timestamp'] and route_data[i-1]['timestamp']:
            if route_data[i]['timestamp'] < route_data[i-1]['timestamp']:
                anomalies.append("⚠️ 시간 역행 감지 (조작 가능성)")

    # 3. 과도한 홉 수
    if len(route_data) > 10:
        anomalies.append(f"⚠️ 과도한 홉 수

댓글

Designed by JB FACTORY