Claude Code 보안 심층 분석 ③ — 탐지 전략: 파일시스템에서 네트워크까지




이 글은 Claude Code 보안 심층 분석 시리즈의 세 번째 편입니다. 전체 시리즈: [1편 조감도] → [2편 위협과 공격 표면] → [3편 탐지 전략] → [4편 통제와 한계] → [5편 놓치기 쉬운 것들]

Claude Code의 디렉토리 구조에 대한 상세 내용은 별도 포스트 「Claude Code .claude 디렉토리 완전 정복」을 참고하세요.


들어가며

2편에서 Claude Code의 위협과 공격 표면을 식별했다. 이 편에서는 핵심 질문에 답한다. “조직 내에서 Claude Code가 사용되고 있는지, 그리고 어떻게 사용되고 있는지를 어떻게 발견하는가?”

탐지는 네 가지 계층으로 접근한다. 파일시스템, 네트워크, 프로세스/시스템, 그리고 Git/SCM이다. 각 계층은 서로 다른 신호를 포착하며, 조합했을 때 가장 포괄적인 가시성을 확보할 수 있다.

1. 파일시스템 기반 탐지: 가장 직접적이고 확실한 방법

Claude Code는 로컬 파일시스템에 풍부한 흔적을 남긴다. .claude 디렉토리와 관련 파일의 존재 여부를 스캔하는 것이 가장 기본적이면서도 확실한 탐지 방법이다.

글로벌 디렉토리 탐지

개발자의 홈 디렉토리에 다음 파일/폴더가 존재하면 Claude Code가 설치되었거나 사용된 적이 있다는 확실한 증거다.

~/.claude/                         # 핵심 — 이것만 있어도 확정
~/.claude.json                     # MCP 서버 설정, OAuth 세션, 환경설정
~/.mcp.json                        # 글로벌 MCP 서버 설정
~/.claude/.credentials.json        # API 인증 (Linux/Windows)
~/.claude/history.jsonl            # 전체 프롬프트 이력
~/.claude/stats-cache.json         # 사용량 통계
~/.claude/projects/                # 프로젝트별 세션 데이터

프로젝트 디렉토리 탐지

소스코드 레포지토리 안에서 다음 파일을 탐지하면, 해당 프로젝트에서 Claude Code가 사용되고 있다는 증거다.

.claude/                           # 프로젝트 설정 디렉토리
.claude/settings.json              # 프로젝트 설정 (팀 공유)
.claude/settings.local.json        # 개인 로컬 설정
.claude/agents/                    # 서브에이전트 정의
.claude/commands/                  # 커스텀 커맨드
.claude/skills/                    # 스킬 정의
.claude/hooks/                     # 훅 스크립트
.claude/rules/                     # 규칙 파일
.mcp.json                          # 프로젝트 MCP 설정
CLAUDE.md                          # 프로젝트 지침
CLAUDE.local.md                    # 개인 프로젝트 지침

종합 탐지 스크립트

다음 스크립트는 단일 엔드포인트에서 Claude Code의 사용 흔적을 종합적으로 스캔한다.

#!/bin/bash
# claude-code-detector.sh
# Claude Code 사용 흔적 종합 탐지 스크립트

echo "============================================="
echo "  Claude Code 사용 탐지 스캔"
echo "  $(date '+%Y-%m-%d %H:%M:%S')"
echo "============================================="
echo ""

FOUND=0

# ─── 1. 글로벌 설치 흔적 ───
echo "[1] 글로벌 설치 흔적 확인"
echo "─────────────────────────"

if [ -d "$HOME/.claude" ]; then
    echo "  ✅ 발견: ~/.claude/ 디렉토리"
    FOUND=$((FOUND + 1))
    
    # 세부 파일 확인
    [ -f "$HOME/.claude/history.jsonl" ] && {
        LINES=$(wc -l < "$HOME/.claude/history.jsonl" 2>/dev/null)
        echo "     ├─ history.jsonl: ${LINES}개 프롬프트 기록"
    }
    [ -f "$HOME/.claude/stats-cache.json" ] && {
        echo "     ├─ stats-cache.json: 사용량 통계 존재"
    }
    [ -f "$HOME/.claude/.credentials.json" ] && {
        echo "     ├─ ⚠️  .credentials.json: API 인증 파일 발견"
    }
    [ -d "$HOME/.claude/projects" ] && {
        PROJ_COUNT=$(ls "$HOME/.claude/projects/" 2>/dev/null | wc -l)
        echo "     ├─ projects/: ${PROJ_COUNT}개 프로젝트 이력"
    }
    [ -d "$HOME/.claude/commands" ] && {
        CMD_COUNT=$(find "$HOME/.claude/commands" -name "*.md" 2>/dev/null | wc -l)
        echo "     ├─ commands/: ${CMD_COUNT}개 글로벌 커맨드"
    }
    [ -d "$HOME/.claude/agents" ] && {
        AGENT_COUNT=$(find "$HOME/.claude/agents" -name "*.md" 2>/dev/null | wc -l)
        echo "     └─ agents/: ${AGENT_COUNT}개 글로벌 에이전트"
    }
else
    echo "  ⬜ 미발견: ~/.claude/ 디렉토리 없음"
fi

[ -f "$HOME/.claude.json" ] && {
    echo "  ✅ 발견: ~/.claude.json (MCP/OAuth 설정)"
    FOUND=$((FOUND + 1))
}
[ -f "$HOME/.mcp.json" ] && {
    echo "  ✅ 발견: ~/.mcp.json (글로벌 MCP 서버)"
    FOUND=$((FOUND + 1))
}

echo ""

# ─── 2. CLI 설치 확인 ───
echo "[2] CLI 설치 확인"
echo "─────────────────"

if command -v claude &>/dev/null; then
    CLAUDE_PATH=$(which claude)
    echo "  ✅ 발견: claude CLI 설치됨 → ${CLAUDE_PATH}"
    FOUND=$((FOUND + 1))
    
    # 버전 확인 시도
    CLAUDE_VER=$(claude --version 2>/dev/null | head -1)
    [ -n "$CLAUDE_VER" ] && echo "     └─ 버전: ${CLAUDE_VER}"
else
    echo "  ⬜ 미발견: claude CLI 미설치"
fi

# npm 글로벌 확인
if npm list -g @anthropic-ai/claude-code 2>/dev/null | grep -q claude-code; then
    echo "  ✅ 발견: npm 글로벌 패키지 설치됨"
    FOUND=$((FOUND + 1))
fi

echo ""

# ─── 3. 프로세스 확인 ───
echo "[3] 실행 중 프로세스 확인"
echo "─────────────────────────"

CLAUDE_PROCS=$(pgrep -fa "claude" 2>/dev/null | grep -v "claude-code-detector" | grep -v grep)
if [ -n "$CLAUDE_PROCS" ]; then
    echo "  ✅ 발견: Claude 관련 프로세스 실행 중"
    echo "$CLAUDE_PROCS" | while read -r line; do
        echo "     └─ $line"
    done
    FOUND=$((FOUND + 1))
else
    echo "  ⬜ 미발견: Claude 프로세스 없음"
fi

echo ""

# ─── 4. 환경 변수 확인 ───
echo "[4] 환경 변수 / 셸 프로파일 확인"
echo "─────────────────────────────────"

for PROFILE in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.bash_profile" "$HOME/.profile"; do
    if [ -f "$PROFILE" ]; then
        ANTHROPIC_REFS=$(grep -c "ANTHROPIC" "$PROFILE" 2>/dev/null)
        CLAUDE_REFS=$(grep -c "CLAUDE" "$PROFILE" 2>/dev/null)
        if [ "$ANTHROPIC_REFS" -gt 0 ] || [ "$CLAUDE_REFS" -gt 0 ]; then
            echo "  ✅ 발견: ${PROFILE} 에 관련 환경 변수"
            grep -n "ANTHROPIC\|CLAUDE" "$PROFILE" 2>/dev/null | while read -r line; do
                echo "     └─ $line"
            done
            FOUND=$((FOUND + 1))
        fi
    fi
done

# ANTHROPIC_BASE_URL 변조 확인
if [ -n "$ANTHROPIC_BASE_URL" ]; then
    if [ "$ANTHROPIC_BASE_URL" != "https://api.anthropic.com" ]; then
        echo "  ⚠️  경고: ANTHROPIC_BASE_URL이 기본값이 아님!"
        echo "     └─ 현재 값: $ANTHROPIC_BASE_URL"
        echo "     └─ API 키 탈취 벡터 가능성 확인 필요"
        FOUND=$((FOUND + 1))
    fi
fi

echo ""

# ─── 5. macOS Keychain 확인 ───
echo "[5] 인증 저장소 확인"
echo "─────────────────────"

if [[ "$OSTYPE" == "darwin"* ]]; then
    if security find-generic-password -s "Claude Code" 2>/dev/null >/dev/null; then
        echo "  ✅ 발견: macOS Keychain에 Claude Code 인증 정보"
        FOUND=$((FOUND + 1))
    elif security find-generic-password -s "Anthropic" 2>/dev/null >/dev/null; then
        echo "  ✅ 발견: macOS Keychain에 Anthropic 인증 정보"
        FOUND=$((FOUND + 1))
    else
        echo "  ⬜ 미발견: Keychain에 관련 항목 없음"
    fi
else
    [ -f "$HOME/.claude/.credentials.json" ] && {
        echo "  ✅ 발견: .credentials.json 파일"
        FOUND=$((FOUND + 1))
    } || echo "  ⬜ 미발견: 인증 파일 없음"
fi

echo ""

# ─── 결과 요약 ───
echo "============================================="
echo "  스캔 결과: ${FOUND}개 항목 발견"
if [ "$FOUND" -gt 0 ]; then
    echo "  ⚠️  Claude Code 사용 흔적이 감지되었습니다."
else
    echo "  ✅ Claude Code 사용 흔적이 없습니다."
fi
echo "============================================="

보안 감사 심화: 설정 파일 내용 검증

단순히 파일 존재 여부를 넘어, 설정 파일의 내용을 검증해야 한다. 특히 공급망 공격 벡터와 관련된 위험 설정을 확인해야 한다.

#!/bin/bash
# claude-config-audit.sh
# Claude Code 설정 파일 보안 감사

echo "=== Claude Code 설정 보안 감사 ==="

# settings.json 내 hooks 검사
for SETTINGS in ".claude/settings.json" "$HOME/.claude/settings.json"; do
    if [ -f "$SETTINGS" ]; then
        echo ""
        echo "📄 ${SETTINGS} 분석:"
        
        # hooks 존재 확인
        if grep -q '"hooks"' "$SETTINGS" 2>/dev/null; then
            echo "  ⚠️  Hooks 설정 발견 — 자동 실행 명령이 정의됨"
            echo "  └─ 악성 명령 포함 여부 수동 검토 필요"
            grep -A5 '"command"' "$SETTINGS" 2>/dev/null | head -20
        fi
        
        # enableAllProjectMcpServers 확인
        if grep -q '"enableAllProjectMcpServers".*true' "$SETTINGS" 2>/dev/null; then
            echo "  🚨 위험: enableAllProjectMcpServers = true"
            echo "  └─ 모든 프로젝트 MCP 서버가 자동 승인됨"
        fi
        
        # dangerouslySkipPermissions 관련
        if grep -q '"disableBypassPermissionsMode"' "$SETTINGS" 2>/dev/null; then
            echo "  ✅ 양호: 권한 우회 모드 비활성화 설정 존재"
        fi
    fi
done

# .mcp.json 검사
for MCP in ".mcp.json" "$HOME/.mcp.json"; do
    if [ -f "$MCP" ]; then
        echo ""
        echo "📄 ${MCP} 분석:"
        
        # 등록된 MCP 서버 목록
        echo "  등록된 MCP 서버:"
        grep -o '"[^"]*"[[:space:]]*:' "$MCP" 2>/dev/null | head -20 | while read -r server; do
            echo "     └─ $server"
        done
        
        # 외부 URL 기반 서버 확인
        if grep -q '"url"' "$MCP" 2>/dev/null; then
            echo "  ⚠️  URL 기반 MCP 서버 발견 — 외부 연결 확인 필요"
            grep '"url"' "$MCP" 2>/dev/null | while read -r url; do
                echo "     └─ $url"
            done
        fi
        
        # env 내 하드코딩된 시크릿 확인
        if grep -qi '"api.key\|token\|secret\|password' "$MCP" 2>/dev/null; then
            echo "  🚨 위험: MCP 설정에 시크릿 하드코딩 의심"
        fi
    fi
done

# ANTHROPIC_BASE_URL 변조 확인 (설정 파일 내)
for SETTINGS in ".claude/settings.json" ".claude/settings.local.json"; do
    if [ -f "$SETTINGS" ]; then
        if grep -q "ANTHROPIC_BASE_URL" "$SETTINGS" 2>/dev/null; then
            echo ""
            echo "  🚨 위험: ${SETTINGS}에서 ANTHROPIC_BASE_URL 오버라이드 발견"
            grep "ANTHROPIC_BASE_URL" "$SETTINGS"
            echo "  └─ API 트래픽 리다이렉트 (키 탈취) 벡터 확인 필요"
        fi
    fi
done

2. 네트워크 기반 탐지: 트래픽 모니터링

핵심 도메인과 엔드포인트

Claude Code가 통신하는 도메인을 네트워크 레벨에서 모니터링한다.

# 핵심 API 통신 (모델 호출)
api.anthropic.com                  # 메인 API 엔드포인트
├── /v1/messages                   # 모델 호출 (소스코드 전송)
├── /api/oauth/usage               # 사용량 확인
└── /v1/organizations/*            # 조직 관리 API

# 텔레메트리
*.statsig.com                      # 운영 메트릭 (Statsig)
*.ingest.sentry.io                 # 에러 리포팅 (Sentry)

# 인증
claude.ai                          # OAuth 로그인 플로우

# User-Agent 식별
User-Agent: claude-code/*          # 예: claude-code/2.0.32

방화벽/프록시 규칙 예시

# 탐지 전용 (로깅만, 차단 안 함)
alert tcp $HOME_NET any -> $EXTERNAL_NET any (
  msg:"Claude Code API 통신 감지";
  content:"api.anthropic.com";
  content:"claude-code/";
  http_header;
  sid:1000001;
)

# 대용량 데이터 전송 탐지
alert tcp $HOME_NET any -> $EXTERNAL_NET any (
  msg:"Claude Code 대용량 요청 감지";
  content:"api.anthropic.com";
  content:"v1/messages";
  http_content_len; content:">100000";
  sid:1000002;
)

페이로드 크기 모니터링

Claude Code의 API 호출은 컨텍스트 윈도우의 크기에 비례하여 상당한 데이터를 전송한다. api.anthropic.com으로의 요청 중 비정상적으로 큰 페이로드(100KB 이상)는 대량의 소스코드가 전송되고 있다는 신호일 수 있다.

프록시에서 api.anthropic.com으로의 요청 크기를 로깅하고, 임계값을 초과하는 요청에 대해 알림을 설정하는 것이 효과적이다.

3. 프로세스 및 시스템 기반 탐지

프로세스 탐지

# Claude Code 프로세스 탐지
ps aux | grep -i "claude" | grep -v grep

# Node.js 기반이므로 node 프로세스에서도 확인
ps aux | grep node | grep -i claude

# MCP 서버 프로세스 탐지 (npx로 실행되는 외부 서버)
ps aux | grep npx | grep -i mcp

시스템 이벤트 모니터링

macOS (Unified Logging):

# Claude Code 관련 로그
log show --predicate 'process == "claude"' --last 24h

# 네트워크 연결 로그
log show --predicate 'processImagePath contains "claude" AND category == "network"' --last 24h

Linux (systemd journal):

# Claude 관련 프로세스 로그
journalctl --since "24 hours ago" | grep -i claude

# 네트워크 소켓 모니터링
ss -tnp | grep -i claude

EDR/엔드포인트 보안 도구 활용

기업 환경에서는 EDR(Endpoint Detection and Response) 도구를 활용하여 다음을 모니터링할 수 있다.

  • claude 바이너리의 실행 이벤트
  • ~/.claude/ 디렉토리에 대한 파일 생성/수정 이벤트
  • api.anthropic.com으로의 아웃바운드 네트워크 연결
  • ANTHROPIC_ 접두사를 가진 환경 변수 설정 이벤트

4. Git/SCM 기반 탐지

커밋 분석

Claude Code는 Git 커밋에 co-authored-by 태그를 남긴다(기본 설정).

# co-authored-by Claude 탐지
git log --all --grep="Co-authored-by.*Claude" --oneline
git log --all --grep="co-authored-by.*Claude" --oneline

# 최근 30일 기준
git log --all --since="30 days ago" --grep="Claude" --oneline

레포지토리 내 Claude 설정 파일 탐지

# .claude 관련 파일이 커밋된 적 있는지
git log --all --diff-filter=A -- '.claude/*' 'CLAUDE.md' 'CLAUDE.local.md' '.mcp.json'

# 현재 브랜치에 존재하는 Claude 관련 파일
find . -name "CLAUDE.md" -o -name "CLAUDE.local.md" \
       -o -name ".mcp.json" -o -path "*/.claude/*" 2>/dev/null

# .gitignore에서 Claude 관련 항목 확인
grep -i "claude" .gitignore 2>/dev/null

PR/MR 리뷰 자동화: 위험 설정 변경 탐지

CI/CD 파이프라인에서 다음 파일의 변경을 자동으로 플래그하는 것이 중요하다.

# GitHub Actions 예시: .claude 설정 변경 탐지
name: Claude Config Security Check
on:
  pull_request:
    paths:
      - '.claude/settings.json'
      - '.claude/settings.local.json'
      - '.mcp.json'
      - '.claude/hooks/**'
      - '.claude/agents/**'
      - 'CLAUDE.md'

jobs:
  security-review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Check for dangerous settings
        run: |
          # hooks 내 command 필드 확인
          if grep -r '"command"' .claude/settings.json 2>/dev/null; then
            echo "::warning::Hooks with commands detected in settings.json"
          fi
          
          # enableAllProjectMcpServers 확인
          if grep -q 'enableAllProjectMcpServers.*true' .claude/settings.json 2>/dev/null; then
            echo "::error::DANGEROUS: enableAllProjectMcpServers is true"
            exit 1
          fi
          
          # ANTHROPIC_BASE_URL 오버라이드 확인
          if grep -q 'ANTHROPIC_BASE_URL' .claude/settings.json 2>/dev/null; then
            echo "::error::DANGEROUS: ANTHROPIC_BASE_URL override detected"
            exit 1
          fi
          
          echo "✅ No dangerous Claude Code settings detected"
      
      - name: Require security team review
        if: failure()
        run: |
          echo "⚠️ This PR modifies Claude Code configuration."
          echo "Security team review is required."

5. 탐지 우선순위 매트릭스

모든 것을 동시에 탐지할 수 없다면, 위험도 기준으로 우선순위를 정해야 한다.

우선순위탐지 대상계층이유
🔴 긴급~/.claude/.credentials.json파일시스템API 키 노출, 무단 사용 비용 발생, Workspace 전체 접근
🔴 긴급api.anthropic.com 트래픽네트워크소스코드/시크릿 외부 전송
🔴 긴급ANTHROPIC_BASE_URL 비기본값환경변수/설정API 키 탈취 벡터 (CVE-2026-21852)
🟠 높음.claude/settings.json 내 hooks파일시스템자동 실행 명령 (CVE-2025-59356)
🟠 높음.mcp.json 미승인 서버파일시스템외부 서비스 무단 연결, MCP 우회 공격
🟠 높음~/.claude/history.jsonl파일시스템전체 프롬프트 이력 — 어떤 데이터가 전송되었는지 사후 감사
🟠 높음~/.claude/projects/파일시스템프로젝트별 전체 대화 기록 (코드 포함)
🟡 중간PR에서 .claude/ 변경Git/SCM공급망 공격 벡터 사전 차단
🟡 중간co-authored-by Claude 커밋Git/SCMAI 생성 코드 추적, 보안 리뷰 대상 식별
🟡 중간Statsig/Sentry 트래픽네트워크텔레메트리 데이터 유출
🔵 참고~/.claude/stats-cache.json파일시스템사용 규모 파악 (세션 수, 토큰 사용량)
🔵 참고claude 프로세스프로세스현재 사용 중 여부 실시간 확인

6. history.jsonl 분석: 사후 감사의 핵심

~/.claude/history.jsonl은 모든 세션의 모든 프롬프트를 시간순으로 기록한 파일이다. 이 파일을 분석하면 어떤 프로젝트에서, 언제, 어떤 내용이 AI에게 전송되었는지 추적할 수 있다.

# history.jsonl 기본 분석
echo "=== 최근 프롬프트 이력 ==="

# 프로젝트별 사용 빈도
jq -r '.project' ~/.claude/history.jsonl 2>/dev/null \
  | sort | uniq -c | sort -rn | head -10

# 최근 7일간 활동
jq -r 'select(.timestamp > (now - 604800) * 1000) | 
  "\(.timestamp / 1000 | strftime("%Y-%m-%d")) | \(.project) | \(.display[:60])"' \
  ~/.claude/history.jsonl 2>/dev/null

# 민감 키워드 포함 프롬프트 탐지
grep -i "password\|secret\|api.key\|token\|credential\|\.env" \
  ~/.claude/history.jsonl 2>/dev/null

projects/ 디렉토리 분석

프로젝트별 세션 데이터는 더 상세한 정보를 제공한다. 전체 대화(Claude의 응답 포함), 파일 수정 이력, 도구 호출 기록이 포함된다.

# 프로젝트별 세션 목록
ls -la ~/.claude/projects/

# 특정 프로젝트의 세션 수
ls ~/.claude/projects/-Users-dev-myproject/ | wc -l

# 세션 메타데이터 (요약, 메시지 수, Git 브랜치)
cat ~/.claude/projects/-Users-dev-myproject/sessions-index.json | jq '.'

7. 탐지 아키텍처 권장 구성

소규모 팀 (5~20명)

주기적 스캔 스크립트를 cron으로 실행하고, 결과를 Slack이나 이메일로 알림한다.

[탐지 스크립트] → cron (주 1회) → [결과 알림]

중규모 조직 (20~200명)

EDR 도구와 네트워크 모니터링을 조합한다.

[EDR 에이전트] → 파일시스템/프로세스 모니터링
[프록시/방화벽] → api.anthropic.com 트래픽 로깅
[CI/CD] → PR에서 .claude/ 변경 자동 탐지
[SIEM] → 로그 집계 및 상관 분석

대규모 엔터프라이즈 (200명 이상)

위의 모든 것에 더해 Anthropic의 Analytics API를 활용한다.

[Analytics API] → 일별 사용자 활동, 세션 수, 터미널 유형
[EDR + 프록시 + CI/CD] → 위와 동일
[DLP 솔루션] → 아웃바운드 데이터 분류 및 차단
[SIEM + SOAR] → 자동화된 탐지-대응 파이프라인

마무리

탐지의 핵심은 계층별 신호를 조합하는 것이다. 파일시스템 스캔은 가장 확실하지만 실시간성이 떨어진다. 네트워크 모니터링은 실시간이지만 HTTPS로 암호화된 내용까지는 보지 못한다. Git 분석은 사후 추적에 강하다. 각 계층의 장단점을 이해하고 조합해야 포괄적 가시성을 확보할 수 있다.

다만 탐지만으로는 충분하지 않다. 탐지 후 무엇을 할 수 있는지, 그리고 무엇을 할 수 없는지를 이해하는 것이 중요하다. 다음 편에서 통제 수단의 가능과 한계를 다룬다.




댓글 남기기