
laravel-threat-detection v1.7.2
SQL 인젝션, XSS, RCE, 봇 스캐너 및 175개 이상의 공격 패턴을 탐지하고 기록하는 패시브 Laravel 미들웨어입니다. 내장 대시보드, Slack 알림, REST API 및 지리 정보 보강 기능을 갖추고 있습니다. WAF가 아닌 IDS입니다.
Laravel Threat Detection
Laravel를 위한 보안 모니터링 및 공격 로깅. SQL 인젝션,
XSS, RCE, 디렉터리 트래버설, 봇 스캐너 및 /wp-admin 스타일의 정찰 프로브를 탐지하고 기록합니다 —
모든 악의적인 요청이 전체 애플리케이션 컨텍스트와 함께 데이터베이스에 기록됩니다.
이것은 IDS이며 WAF가 아닙니다: 요청을 차단, 필터링 또는 수정하지 않습니다.
다음과 같은 것을 보고 여기에 오셨나요?
GET /wp-admin/setup-config.php 404 — on a site that isn't WordPress
GET /.env 404 — someone wants your database password
GET /?id=1' UNION SELECT password FROM 200 — SQL injection against a real route
GET /phpmyadmin/index.php 404 — scanning for an admin panel
이러한 요청들은 이미 Laravel 앱에 도달하고 있습니다. 액세스 로그에는 URL과 상태 코드만 표시될 뿐, 디코딩된 페이로드도, 어떤 라우트가 공격 대상이었는지도, 동일한 IP가 이번 시간에 다른 40가지 시도를 했는지도 알 수 없습니다.
이 패키지가 그 질문들에 답합니다. Laravel 10–13 앱 어디에든 설치하면 모든 HTTP 요청을 150개 이상의 공격 패턴과 대조해 스캔하기 시작하고, 각 일치 항목을 신뢰도에 따라 점수화하여 데이터베이스에 기록합니다 — 내장 대시보드, Slack 알림, 지리 정보 보강, fail2ban/차단 목록 내보내기 기능까지 갖추고 있습니다. 어떤 요청도 차단되지 않습니다. 자물쇠가 아니라 보안 카메라라고 생각하세요: 누가, 얼마나 자주, 어떤 기법으로 라우트를 탐색하는지 정확히 보여줍니다.
프로덕션 앱에서 추출되어 실제 트래픽에서 검증되었습니다. 2,400개 이상의 테스트, Laravel 자체 외 런타임 의존성 없음, 탐지에 인터넷 연결이 필요하지 않습니다.
업그레이드하시나요? UPGRADING.md를 참조하세요. 기여하시나요? CONTRIBUTING.md를 참조하세요.
1분 이내에 시작하기
composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate
그런 다음 미들웨어를 web 그룹에 추가하세요 (Laravel 11+에서는 bootstrap/app.php에 한 줄, Laravel 10에서는 app/Http/Kernel.php에 한 줄) — 전체 스니펫은 아래 Quick Start에 있습니다.
이게 전부입니다. 탐지가 활성화됩니다.
php artisan threat-detection:doctor # confirms it is actually recording
어디에 적합한가: IDS vs WAF vs 엣지
이 패키지는 수동적, 애플리케이션 수준 IDS입니다 — 감시하고 기록할 뿐, 차단하지 않습니다. WAF나 엣지 서비스를 대체하는 것이 아니라 함께 위치하도록 설계되었습니다. 각 계층은 다른 계층이 볼 수 없는 것을 봅니다:
| 이 패키지 (앱 IDS) | WAF (ModSecurity + OWASP CRS, Cloudflare WAF) | 엣지 / CDN (Cloudflare) | |
|---|---|---|---|
| 악성 요청 차단 | ❌ 로그만 기록 | ✅ | ✅ |
| 전체 앱 컨텍스트 (정확한 URL, 디코딩된 페이로드, 인증된 사용자) | ✅ | ⚠️ 부분적 | ❌ |
| 내장 대시보드 + DB 내 위협 로그 | ✅ | ⚠️ 경우에 따라 다름 | ⚠️ 엣지만 |
| 앱 특화 탐지 (예: Aadhaar / PAN / IFSC PII) | ✅ 내장 + 사용자 정의 | ⚠️ 직접 규칙 작성 | ⚠️ 사용자 정의 규칙, 플랜 의존 |
| 오프라인 / 외부 서비스 불필요 | ✅ | ⚠️ 의존 | ❌ |
| 트래픽이 서버에 도달하기 전 차단 | ❌ | ⚠️ 클라우드 WAF만 | ✅ |
| 설정 | composer require, 마이그레이션, 미들웨어 한 줄 | 중간–높음 | 낮음–중간 |
| 비용 | 무료, MIT | 경우에 따라 다름 | 무료 티어 + 유료 |
요약하자면: 엣지/WAF는 문에 달린 자물쇠이고, 이것은 내부의 보안 카메라로, 어떤 라우트에 누가 얼마나 자주 무엇을 시도하는지 정확히 알려줄 앱 컨텍스트를 갖추고 있습니다. 엣지 계층이 결코 볼 수 없는 데이터로 실제 결정 — fail2ban 차단, 속도 제한, 지역 차단 — 을 내리는 데 활용하세요.
의도적으로 아닌 것
- WAF가 아닙니다. 요청을 차단, 필터링, 수정하지 않습니다. 강제 적용에는 Cloudflare, mod_security 또는 실제 WAF를 사용하세요. (넘겨줄 엣지 계층이 없나요? 운영자 측 헬퍼가 패키지의 결정을 노출하므로 직접 다섯 줄짜리 차단 미들웨어를 작성할 수 있습니다 — 강제 적용 코드는 패키지가 아닌 여러분의 것입니다.)
- 안전한 코딩을 대체하지 않습니다. 매개변수화된 쿼리, 입력 검증, 출력 이스케이프가 실제 방어입니다. 이 패키지는 여러분의 코드가 이미 안전하다고 가정하고 가시성을 제공할 뿐, 보호를 제공하지 않습니다.
- 엣지 서비스가 아닙니다. Cloudflare를 앞에 둘 수 있다면 두고, 그런 다음 엣지 서비스가 볼 수 없는 애플리케이션 수준 세부 정보를 위해 이것을 추가하세요.
- 완전한 탐지기가 아니며, 그럴 수도 없습니다. 패턴 매칭은 알려진 공격처럼 보이는 공격을 잡습니다. 새로운 기법이나 충분히 재작성된 익숙한 기법은 기록되지 않고 통과할 것이며, 통과했다는 사실조차 알려지지 않습니다. 여기서의 침묵은 "아무것도 일치하지 않았다"는 뜻이지 "아무 일도 일어나지 않았다"는 뜻이 아닙니다. 이 패키지가 가치를 발휘하는 곳은 공개 Laravel 앱에 실제로 도달하는 트래픽의 대부분을 차지하는 대량·저노력 트래픽입니다: 스캐너, 정찰 프로브, 기성 주입 문자열, 자격 증명 스프레이. 조용한 로그를 증거의 부재로 취급하지 말고, 부재의 증거로 취급하세요.
첫날부터 여러분의 자체 콘텐츠를 탐지할 것으로 예상하세요
튜닝되지 않은 설치 환경은 정상적인 콘텐츠에도 반응하며, 설치 후가 아니라 설치
전에 이를 알아야 합니다. 이는 가정이 아니라 측정된 결과입니다. 아래 행은
LegitimateTrafficCorpusTest가
고정한 하한선의 일부이며, 각 행은 해당 요청이 기록하는 모든 것을 나열하고,
ReadmeNoiseFloorTest는
어떤 행이든 해당 스위트가 측정하는 것과 일치하지 않게 되면 빌드를
실패시킵니다.
| 완벽하게 정상적인 요청 | 튜닝되지 않은 설치가 기록하는 것 |
|---|---|
검색창에 입력한 how to write a UNION SELECT in postgres | SQL Injection UNION / high |
<script>window.dataLayer=[];</script>를 포함한 블로그 게시물 | XSS Script Tag / high · Command Chain Injection / medium |
SELECT * FROM users WHERE id = 1 오류를 붙여넣은 지원 티켓 | SQLi Variant / high · SQL SELECT Query / low |
../../etc/passwd가 고전적인 트래버설 페이로드라고 설명하는 문서 | Directory Traversal / medium · Sensitive File Access / medium |
| 실제 인도 휴대폰 번호와 PAN을 수집하는 프로필 양식 | PAN Number Detected / high · Bank Account Number Detected / high · Mobile Number Detected / low |
이 중 어느 것도 버그가 아닙니다. <script>를 포함한 블로그 게시물은 바이트
단위로 저장형 XSS 페이로드이고, UNION SELECT 검색은 그 시도와 구별할 수
없으며, 열 자리 휴대폰 번호는 그럴듯한 은행 계좌 번호이기도 합니다. 애플리케이션
컨텍스트 외에는 이들을 구분하는 것이 없으며, 어떤 패턴 엔진도 여러분을 위해 그
컨텍스트를 제공할 수 없습니다.
컨텍스트를 제공하는 것은 한 줄짜리 설정 변경입니다: 그러한 콘텐츠를 정당하게
담는 필드를 safe_fields에 (또는 중첩 JSON 내부의 한 경로에 대해서는
safe_paths에) 지정하면 더 이상 스캔되지 않습니다. 이것이 위의 행들을 조용하게
만드는 스위치이며 — 그리고 그것은 실제 트레이드오프입니다. 왜냐하면 그 필드를
통해 전달되는 공격도 보이지 않게 되기 때문입니다.
content_paths와 relaxed 모드는 다른 도구입니다. 이들은 낮음 및 중간 심각도
노이즈를 제거하고 의도적으로 높은 심각도 일치를 계속 기록합니다 — 따라서
설계상 이 표의 높은 심각도 행들을 조용하게 만들지 않습니다. 언제 무엇을
사용해야 하는지는 오탐 줄이기를 참조하세요.
여러분의 앱이 리치 텍스트, 코드 샘플 또는 검색 쿼리를 받아들인다면, 출력을 판단하기 전에 그렇게 하세요. 기본값은 조용하고 불완전하기보다 의도적으로 시끄럽지만 정직합니다: 알려진 일치를 조용하게 만드는 것이 결코 발생하지 않은 일치를 발견하는 것보다 쉽습니다.
그래서 실제로 무엇을 하는가?
결코 차단하지 않는 탐지기에 대해 가장 흔한 질문입니다. 노력이 증가하는 순서로 네 가지 답이 있습니다: