security
CHAPTER 66 / 84
읽기 약 2분
FUNCTION
보안 헤더 자동 점검 도구 만들기
핵심 개념
지금까지 배운 것을 종합해서 — 웹사이트의 보안 헤더를 자동 점검하는 CLI 도구를 만든다.
본문
종합 프로젝트: secheader CLI
이 챕터에서 만드는 것은 실용 가치 있는 미니 도구입니다.
$ python secheader.py --url https://github.com
✅ Strict-Transport-Security: max-age=31536000
✅ X-Frame-Options: deny
✅ X-Content-Type-Options: nosniff
⚠️ Content-Security-Policy: 너무 약함 (unsafe-inline 포함)
❌ Referrer-Policy: 누락
점수: 3.5/5.0 (Warn)전체 구현
# ⚠️ 이 코드는 허가된 환경에서만 사용하세요.
# secheader.py — 보안 헤더 자동 점검 CLI
import argparse
import json
import sys
import logging
from typing import Optional
import requests
log = logging.getLogger('secheader')
CHECKS = {
'Strict-Transport-Security': {
'required': True,
'recommended': 'max-age=31536000; includeSubDomains',
'description': 'HTTPS 강제 (HSTS)',
},
'Content-Security-Policy': {
'required': True,
'recommended': "default-src 'self'",
'description': 'XSS 방어 (CSP)',
'warn_if': lambda v: 'unsafe-inline' in v or 'unsafe-eval' in v,
'warn_msg': 'unsafe-inline/unsafe-eval 포함 — XSS 위험',
},
'X-Frame-Options': {
'required': True,
'recommended': 'DENY',
'description': '클릭재킹 방어',
},
'X-Content-Type-Options': {
'required': True,
'recommended': 'nosniff',
'description': 'MIME 스니핑 방어',
},
'Referrer-Policy': {
'required': True,
'recommended': 'strict-origin-when-cross-origin',
'description': 'Referer 정보 제어',
},
'Permissions-Policy': {
'required': False,
'recommended': 'geolocation=(), microphone=()',
'description': '브라우저 API 권한 제어',
},
}
def check_url(url: str, timeout: float = 5.0) -> dict:
"""단일 URL의 보안 헤더 점검."""
try:
r = requests.get(
url,
timeout=timeout,
allow_redirects=True,
headers={'User-Agent': 'secheader/1.0 (security audit)'},
)
except requests.exceptions.RequestException as e:
return {'url': url, 'error': str(e)}
results = []
score = 0.0
max_score = 0.0
for header, spec in CHECKS.items():
weight = 1.0 if spec['required'] else 0.5
max_score += weight
value = r.headers.get(header)
result = {
'header': header,
'description': spec['description'],
'present': value is not None,
'value': value,
'status': 'PASS',
'note': None,
}
if value is None:
result['status'] = 'FAIL' if spec['required'] else 'WARN'
result['note'] = f"권장: {spec['recommended']}"
else:
result['status'] = 'PASS'
score += weight
# 약한 설정 경고
if 'warn_if' in spec and spec['warn_if'](value):
result['status'] = 'WARN'
result['note'] = spec.get('warn_msg', '약한 설정')
score -= weight * 0.5 # 부분 감점
results.append(result)
return {
'url': r.url,
'final_url': r.url,
'status_code': r.status_code,
'score': round(score, 1),
'max_score': round(max_score, 1),
'percentage': round(score / max_score * 100, 1),
'grade': grade(score / max_score),
'checks': results,
}
def grade(ratio: float) -> str:
if ratio >= 0.9: return 'A (Excellent)'
if ratio >= 0.75: return 'B (Good)'
if ratio >= 0.5: return 'C (Warn)'
if ratio >= 0.25: return 'D (Poor)'
return 'F (Critical)'
def print_report(report: dict) -> None:
"""사람이 읽기 쉬운 콘솔 출력."""
if 'error' in report:
print(f"❌ {report['url']}: {report['error']}")
return
print(f"\n🔍 {report['url']}")
print(f" 상태 코드: {report['status_code']}")
print(f" 점수: {report['score']}/{report['max_score']} ({report['percentage']}%) — {report['grade']}")
print()
for check in report['checks']:
icon = {'PASS': '✅', 'WARN': '⚠️ ', 'FAIL': '❌'}[check['status']]
line = f" {icon} {check['header']}"
if check['value']:
line += f": {check['value'][:60]}"
if check['note']:
line += f"\n → {check['note']}"
print(line)
def main():
parser = argparse.ArgumentParser(description='웹사이트 보안 헤더 자동 점검 도구')
parser.add_argument('--url', '-u', required=True, help='점검할 URL (https://example.com)')
parser.add_argument('--json', '-j', action='store_true', help='JSON 형식 출력')
parser.add_argument('--output', '-o', help='결과 저장 파일 경로')
parser.add_argument('--timeout', '-t', type=float, default=5.0)
parser.add_argument('--verbose', '-v', action='store_true')
args = parser.parse_args()
logging.basicConfig(
level=logging.DEBUG if args.verbose else logging.WARNING,
format='%(asctime)s [%(levelname)s] %(message)s',
)
report = check_url(args.url, timeout=args.timeout)
if args.json:
out = json.dumps(report, indent=2, ensure_ascii=False)
print(out)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(out)
else:
print_report(report)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(json.dumps(report, indent=2, ensure_ascii=False))
# exit code: 0=PASS, 1=WARN, 2=FAIL
if 'error' in report or report.get('grade', '').startswith('F'):
sys.exit(2)
if 'WARN' in str(report.get('checks', [])) or report.get('grade', '').startswith(('C', 'D')):
sys.exit(1)
sys.exit(0)
if __name__ == '__main__':
main()사용 예시
# 기본 점검
$ python secheader.py --url https://github.com
# JSON 리포트 저장
$ python secheader.py --url https://example.com --json --output report.json
# CI/CD 파이프라인 통합 (exit code 활용)
$ python secheader.py --url https://my-app.com || echo "보안 헤더 미흡!"확장 아이디어
배운 내용으로 더 발전시킬 수 있는 방향:
- 여러 URL 일괄 점검 —
--urls-file targets.txt - CSV/HTML 리포트 — 경영진 보고용
- GitHub Actions 통합 — PR마다 자동 점검
- SecurityHeaders.com API 연동 — 비교 점수
- OWASP ZAP 연계 — 더 깊은 점검
🎯 다음 트랙: 모듈 3 ~ 7
지금 배운 것은 보안 도구 제작의 기초 12챕터입니다. 후속 모듈에서:
- 모듈 3: 네트워크 스캐닝 (socket, scapy)
- 모듈 4: 웹 취약점 자동 탐지 (SQLi, XSS)
- 모듈 5: 암호학 실습 (cryptography)
- 모듈 6: 시스템 보안 (paramiko, OS hardening)
- 모듈 7: 자동화 + CTF 실전
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내가 만든 secheader 도구의 예외 처리·재사용성·확장성을 코드 리뷰해주고 프로덕션 수준으로 리팩토링해줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
argparse + requests + json 조합으로 다른 보안 도구(포트 스캐너/SSL 점검/JWT 분석기)를 비슷한 구조로 만드는 템플릿을 보여줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 secheader 코드 전체를 분석해서 메모리 사용·네트워크 효율·동시성을 100개 도메인 일괄 점검에 최적화하도록 개선해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 보안 헤더 자동화 도구 시장 — Mozilla Observatory/SecurityHeaders.com 같은 SaaS와 자체 도구의 트레이드오프를 솔직히 알려줘.
⭐ 이것만 기억하세요
보안 헤더 자동 점검 도구 만들기는 이 3가지만 확실히 잡으세요
1.12개 챕터의 모든 기법(requests/BeautifulSoup/argparse/logging/예외처리)을 종합해 실용 가치 있는 보안 도구를 완성했다
2.argparse + JSON 리포트 + exit code로 CI/CD 파이프라인에 통합 가능한 수준의 도구다
3.다음 모듈(3~7)에서 네트워크 스캐닝·웹 취약점·암호학·시스템 보안·CTF로 확장한다
공유하기
진행도 66 / 84