9. 보안 구성 (core/Secure.php 전담)
| 영역 | 내용 |
|---|---|
| 헤더 | X-Frame-Options: SAMEORIGIN, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, X-XSS-Protection, Permissions-Policy: camera=(), microphone=(), geolocation=(), HTTPS 시 HSTS 1년 + includeSubDomains, X-Powered-By 제거 |
| CSP | default-src 'self'; script-src 'self' 'unsafe-inline' https: blob:; style-src 'self' 'unsafe-inline' https: data:; img-src 'self' data: https: blob:; font-src 'self' data: https:; connect-src 'self' https: wss: ws:; media-src/frame-src https:; worker-src 'self' blob:; object-src 'none' |
| WAF | SQLi·XSS·LFI·CMD 정규식. POST 본문 제외 필드: content, body, description, editor_content, comment, message, text, detail, intro, post_content, reply, html, summary |
| 레이트리밋 | 일반 10초 60회, IP당 1분 200회. Redis rl:* 키 또는 data/cache/rl_*.tmp 파일 |
| IP 밴 | Redis가 있을 때만 dx:ban:{ip} 로 30분 차단. Redis가 없으면 밴 저장소가 없다 |
| 봇 | 허용 봇 화이트리스트(Googlebot, Yeti, bingbot, DuckDuckBot, Baiduspider, kakaotalk-scrap, facebookexternalhit, Twitterbot, LinkedInBot, AhrefsBot, SemrushBot). curl/wget/python/scrapy/headless/selenium/phantomjs UA는 경고 로그만 남김(차단 아님) |
| 업로드 | MIME 화이트리스트(jpeg, png, gif, webp, bmp, pdf, doc/docx, xls/xlsx, zip, txt), 이중 확장자 차단, getimagesize 이미지 검증 |
| 비밀번호 | bcrypt (password_hash) |
| 키 | Secure.php는 설치마다 고유 경로(core/security/{hash}/)에서 로드. 파일이 없으면 core/Secure.php로 폴백 |
| 입력 정제 | DxSanitizer — 주석은 DOMDocument 기반이라 하지만 실제 구현은 preg_replace 정규식 기반(<script> 등 태그 제거, on*= 제거, blocked: 차단, data: src 제거, <?php 제거) |