BotDetect v2 — 프로덕션 봇 탐지 라이브러리
클라이언트 측 봇 및 자동화 탐지 라이브러리로, 가중치 기반 점수 산정, 행동 분석, 브라우저 지문 인식, 설정 가능한 임계값을 제공합니다. 헤드리스 브라우저, Selenium, Puppeteer, Playwright, CDP 기반 도구, 스텔스 자동화 프레임워크를 탐지합니다.
v2.1.0 — 탐지 방지 허니팟, GPU 안정적 캔버스 지문 인식, 향상된 행동 분석, 지연 초기화, 서버 측 변조 탐지, 요청 지문 바인딩, 속도 제한.
목차
기능
- 28개의 탐지 모듈 — 자동화 프레임워크, 헤드리스 브라우저, 지문 인식, 행동 분석, 허니팟, 스택 트레이스 트랩 포함
- 가중치 기반 점수 시스템 — 각 신호에 구성 가능한 가중치 할당, 최종 점수는 서버에서 계산
- 세 가지 판정 수준:
human, suspicious, bot 및 해당 마찰 조치 (monitor, challenge, block)
- 서버 측 검증 — 논스 게이트, 재생 방지, 작업 증명 서명
- 스택 트레이스 트랩 — DOM API를 몽키패치하여 자동화 도구 호출 스택 캡처
- 행동 분석 — 마우스 곡률, 키 입력 타이밍 분산, 스크롤 가속도, 터치 동역학
- 탐지 방지 허니팟 — 무작위 CSS 은닉, 미끼 필드, 현실적인 필드 이름
- 서버 측 변조 탐지 — 신호 무결성 검증, 게이밍 시도 탐지
- 요청 지문 바인딩 — PoW 토큰을 HTTP 요청 속성에 바인딩
- 속도 제한 — 모든 검증 엔드포인트에 대해 세션별 속도 제한
- 스크립트 미지원 탐지 — 탐지 페이로드를 전혀 보내지 않는 클라이언트 식별
- 알려진 크롤러 허용 목록 — 20개 이상의 합법적인 봇을 점수 산정에서 제외
아키텍처
Browser Your Server
┌──────────────────────────┐ ┌──────────────────────┐
│ Collector (singleton) │ POST │ Express Middleware │
│ ├─ 28 detection modules│ signals │ ├─ NonceManager │
│ ├─ BehaviorTracker │ + nonce │ ├─ RateLimiter │
│ ├─ HoneypotTraps │───────────▶│ ├─ TamperDetector │
│ ├─ Stack trace traps │ │ ├─ computeVerdict() │
│ └─ IframeContext │ │ └─ Proof-of-Work │
│ │ verdict │ │
│ ↓ collect() → │ + proof │ Returns: │
│ DetectionResult[] │◀───────────│ { verdict, score, │
└──────────────────────────┘ │ confidence, proof, │
│ tamperScore } │
└──────────────────────┘
│
▼
Session-gated endpoint
(login, checkout, etc.)
validates proof before
granting access
핵심 원칙: 브라우저는 원시 DetectionResult[] 신호만 수집합니다. 서버는 비밀 가중치 테이블을 사용하여 최종 판정을 계산합니다. 클라이언트가 계산한 판정은 절대 신뢰하지 않습니다.
빠른 시작
1. 빌드
npm install
npm run build
dist/에 출력:
botdetect.min.js (폴리필 포함, ~151 KB)
botdetect-clean.min.js (최신 브라우저 전용, ~74 KB)
2. 페이지에 포함
<script src="/path/to/botdetect.min.js"></script>
<script>
BotDetect.collector.enableTraps();
BotDetect.collector.enableBehavioralTracking();
BotDetect.collector.enableHoneypots();
</script>
3. 서버 측 검증 설정
cd server
npm install express cors express-session
node example-integration.js
4. 민감한 작업 시 신호 전송
async function onLogin() {
const { nonce } = await (await fetch('/api/botdetect/nonce')).json();
BotDetect.collector.setNonce(nonce);
const signals = await BotDetect.collector.collect();
const resp = await fetch('/api/botdetect/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ signals, nonce })
});
const { verdict, score, proof, friction } = await resp.json();
document.getElementById('botdetect-proof').value = proof;
document.getElementById('login-form').submit();
}
5. 서버에서 검증
app.post('/api/login', (req, res) => {
const bd = req.session.botdetect;
if (!bd) return res.status(403).json({ error: 'no_verification' });
if (bd.verdict === 'bot') return res.status(403).json({ error: 'access_denied' });
if (bd.verdict === 'suspicious') return challengeCaptcha(req, res);
res.json({ success: true });
});
클라이언트 측 API
Collector (싱글턴)
import Collector from './collector/Collector';
// 또는 전역: BotDetect.collector
Detector (디버그 전용)
import Detector from './detector/Detector';
경고: analyze()는 브라우저에서 전적으로 실행됩니다. 프로덕션 결정에 절대 사용하지 마십시오.
타입
interface DetectionResult {
name: string; // 모듈 이름
score: number; // 0.0 – 1.0
weight: number; // 1 – 10 (중요도)
detail?: string; // 사람이 읽을 수 있는 설명
}
interface DetectionVerdict {
verdict: 'bot' | 'suspicious' | 'human';
score: number; // 0.0 – 1.0
confidence: number; // 0.0 – 1.0
signals: DetectionResult[];
threshold: number;
friction: 'monitor' | 'challenge' | 'block';
}
interface CollectorConfig {
detectionTimeoutMs: number; // 모듈당 타임아웃 (기본값: 3000)
enableTraps: boolean;
enableBehavioralTracking: boolean;
enableHoneypots: boolean;
thresholds: { strict: number; balanced: number; relaxed: number };
}
서버 측 통합
Express 미들웨어
const { createBotDetectEndpoint } = require('./server');
const { router, generateProofOfWork, cleanup } = createBotDetectEndpoint({
secretSalt: process.env.BOTDETECT_SALT,
scoring: {
threshold: 'balanced', // 'strict' | 'balanced' | 'relaxed' | number
minSignals: 2,
signalBoostThreshold: 0.8,
frictionThresholds: { monitor: 0.2, challenge: 0.5, block: 0.8 }
},
nonce: { ttl: 300000 }, // 5분 논스 만료
noScript: { timeout: 10000 }, // 10초 스크립트 미지원 윈도우
rateLimit: { maxRequests: 10, windowMs: 60000 },
noScriptPaths: ['/api/login', '/api/checkout', '/api/register']
});
app.use('/api', router);
엔드포인트
| 엔드포인트 | 메서드 | 목적 |
|---|
/api/botdetect/nonce | GET | 일회용 논스 발급 |
/api/botdetect/verify |
서버 응답 형식
{
"verdict": "human",
"score": 0.125,
"confidence": 0.85,
"tamperScore": 0,
"friction": "monitor",
"threshold": 0.5,
"proof": "a1b2c3d4e5f6..."
}
서버 측 점수 산정 (Node.js)
const { computeVerdict, RateLimiter, NonceManager } = require('./scoring');
const verdict = computeVerdict(signals, {
threshold: 'balanced',
minSignals: 2,
signalBoostThreshold: 0.8,
frictionThresholds: { monitor: 0.2, challenge: 0.5, block: 0.8 }
});
// verdict.tamperScore > 0 이면 신호 변조 감지
탐지 모듈
자동화 프레임워크 (가중치 5–7)
Playwright 전용 (가중치 3–4)
| 모듈 | 탐지 대상 | 가중치 |
|---|
playwrightWebKit | WebKit 자동화 아티팩트 | 4 |
playwrightOrientation | 방향 + chrome.runtime 불일치 | 3 |
행동 분석 (가중치 7)
| 모듈 | 분석 신호 | 가중치 |
|---|
behavioralAnalysis | 마우스 곡률 + 직선 비율, 키 입력 CV + 버스트 패턴 + KPM, 스크롤 가속도 + 방향 변화, 터치 힘 분산 + 반경 | 7 |
브라우저 지문 인식 (가중치 3–4)
Navigator 및 OS 속성 (가중치 5)
| 모듈 | 확인 항목 | 가중치 |
|---|
navigatorInconsistencies | 11개 확인: languages, plugins, mimeTypes, platform, UA, cookies, DNT, touch, hardwareConcurrency, deviceMemory, connection | 5 |
화면 및 성능 (가중치 3)
활성 트랩 및 허니팟 (가중치 8–9)
| 모듈 | 탐지 대상 | 가중치 |
|---|
honeypotTraps | 무작위 숨김 필드 + 미끼 + 카나리 엔드포인트 | 9 |
stackTraceTraps | // 호출자 스택 분석 |
네트워크 및 컨텍스트 (가중치 1–2)
허용 목록 (가중치 0)
| 모듈 | 탐지 대상 | 가중치 |
|---|
verifiedBots | 20개 이상의 알려진 크롤러 (Googlebot, Bingbot, Yandex, Facebook, Twitter 등) — -1 반환, 점수 산정에서 제외 | 0 |
설정
Collector
const collector = Collector.getInstance({
detectionTimeoutMs: 1000, // 더 빠른 UX를 위해 낮춤
enableTraps: true,
enableBehavioralTracking: true,
enableHoneypots: true,
thresholds: {
strict: 0.3, // 공격적 (로그인, 체크아웃)
balanced: 0.5, // 기본값
relaxed: 0.7 // 관대함 (콘텐츠 탐색)
}
});
Detector (디버그 전용)
const detector = Detector.getInstance({
threshold: 'balanced', // 'strict' | 'balanced' | 'relaxed' | number
minSignals: 2, // 부스트 전 최소 신호 수
signalBoostThreshold: 0.8, // 이 값 이상의 신호는 추가 가중치 획득
failPolicy: 'open', // 'open' = 오류 시 human, 'closed' = 오류 시 bot
frictionThresholds: {
monitor: 0.2,
challenge: 0.5,
block: 0.8
}
});
서버
createBotDetectEndpoint({
secretSalt: process.env.BOTDETECT_SALT, // 비밀로 유지
scoring: { threshold: 'balanced' },
nonce: { ttl: 300000, cleanupInterval: 60000 },
noScript: { timeout: 10000 },
rateLimit: { maxRequests: 10, windowMs: 60000 },
requestFingerprint: true, // PoW를 요청 속성에 바인딩
noScriptPaths: ['/api/login', '/api/checkout']
});
프로덕션 체크리스트
보안
성능
모니터링
테스트
npm test # 6개 스위트에 걸친 74개의 Jest 테스트
npm run typecheck # TypeScript strict 모드
npm run lint # ESLint
npm run build # Webpack 프로덕션 번들
라이선스
Apache — Lahmeri Mohamed Amine