여러 검증 레이어를 지원하는 유연하고 확장 가능한 CAPTCHA 프레임워크입니다. 기존 캡차와 달리, Kanadi는 번들에 있는 모든 챌린지를 완료해야 검증이 완료됩니다.
- 멀티 레이어 검증: 여러 validator를 번들로 묶어서 체인 형태로 검증
- 커스텀 Validator:
@Validator데코레이터로 직접 validator 제작 가능 - 내장 Validator: Proof of Work (PoW), 브라우저 검증 등 기본 제공
- 강력한 Ban 시스템: IP/CIDR/ASN/Device/User 단위 차단, Redis 캐싱
- NestJS 통합: NestJS 애플리케이션과 완벽하게 통합
- 데이터베이스 지원: Redis와 PostgreSQL을 이용한 세션 관리
- 유연한 아키텍처: 모듈화된 설계로 쉬운 커스터마이징
npm install kanadi
# 또는
bun add kanadiimport { KanadiGateway, KanadiClient, KanadiContext } from 'kanadi/gateway';
import { PSQLDatabaseConfig, RedisDatabaseConfig } from 'kanadi/database';
import { PowV2Validator } from 'kanadi/validators';
@KanadiGateway({
namespace: "captcha",
config: [
PSQLDatabaseConfig.forRoot({
url: "postgres://user:password@localhost:5432/captcha"
}),
RedisDatabaseConfig.forRoot({
host: "localhost",
password: "your-password",
port: 6379
})
],
validators: [
PowV2Validator
]
})
export class CaptchaGateway {
constructor(private readonly client: KanadiClient) {}
async handleOnChallengeCreated(context: KanadiContext) {
// 챌린지 번들 생성
const bundle = await context.createBundle('my-bundle-id');
// 번들에 middleware 추가
await bundle.add('pow_v2', {
difficulty: 5,
data: 'challenge-data'
});
// 번들 발행
await bundle.publish();
// 챌린지 발급
return await context.challenge({
bundleId: bundle,
timeout: 10000
});
}
async handleOnChallengeValidated(context: KanadiContext) {
return await context.validate();
}
}import { Module } from '@nestjs/common';
import { CaptchaGateway } from './kanadi.gateway';
@Module({
imports: [CaptchaGateway], // 그냥 직접 import하면 됩니다!
})
export class AppModule {}주의:
@KanadiGateway데코레이터가 자동으로 NestJS Module로 변환하므로,forRoot()나 다른 설정 없이 바로 imports에 추가할 수 있습니다.
import { Validator, IChallengeValidator, ChallengeContext, ChallengeStep, StepValidationResult, ChallengeResult } from 'kanadi/middleware';
import { Injectable } from '@nestjs/common';
@Injectable()
@Validator({
id: 'my_validator',
name: '내 커스텀 Validator',
priority: 5,
required: true,
category: 'custom',
description: '커스텀 검증 로직'
})
export class MyValidator implements IChallengeValidator {
generateChallenge(context: ChallengeContext): ChallengeStep {
return {
solveId: 'unique-solve-id',
validatorId: 'my_validator',
validatorName: '내 커스텀 Validator',
data: {
// 클라이언트에게 전달할 챌린지 데이터
},
timeout: 30
};
}
async validate(
context: ChallengeContext,
solveId: string,
submittedData: any
): Promise<StepValidationResult> {
// 검증 로직
return {
solveId,
validatorId: 'my_validator',
validatorName: '내 커스텀 Validator',
result: ChallengeResult.PASS,
score: 100,
confidence: 0.95,
processingTime: 10,
evidence: {},
timestamp: new Date()
};
}
canExecute(context: ChallengeContext): boolean {
return true;
}
calculateDifficulty(context: ChallengeContext): number {
return 5;
}
}프레임워크가 자동으로 다음 엔드포인트를 생성합니다:
새로운 챌린지 세션을 생성합니다.
응답:
{
"status": "Challenge created successfully",
"sessionId": "session-id",
"challenge": {
"id": "challenge-id"
},
"timeout": 10000
}챌린지 응답을 검증합니다.
요청 본문:
{
"sessionId": "session-id",
"challengeId": "challenge-id",
"response": {}
}응답:
{
"status": "success"
}- kanadi/validator: Validator 데코레이터와 인터페이스
- kanadi/gateway: Gateway 데코레이터와 클라이언트 관리
- kanadi/database: 데이터베이스 설정 (Redis, PostgreSQL)
- kanadi/models: Redis OM과 Prisma를 위한 데이터 모델
- kanadi/validators: 내장 validator들
- 클라이언트가 챌린지 요청
- Gateway가 지정된 validator들로 번들 생성
- 각 validator가 챌린지 생성
- 클라이언트가 모든 챌린지 해결
- Gateway가 모든 응답 검증
- 모든 validator를 통과하면 캡차 완료
계산 작업을 요구하는 Proof of Work validator입니다.
await bundle.add('pow_v2', {
difficulty: 5, // 0-10, 높을수록 어려움
data: 'challenge-data'
});강력한 차단 시스템으로 악의적인 요청을 효과적으로 차단할 수 있습니다.
- IP/CIDR 차단: 단일 IP 또는 IP 대역 차단 (
192.168.1.0/24) - ASN 차단: 전체 네트워크 차단 (
AS54115) - Device/User 차단: 디바이스 및 사용자 단위 차단
- Session 차단: 세션과 연관된 모든 엔티티 차단
- Redis 캐싱: 밀리초 단위 조회 성능
- 자동 만료: 임시/영구 차단 지원
import { Ban } from 'kanadi/ban';
await Ban.IP('192.168.1.100', {
reason: 'Spam attack',
durationMinutes: 60
});
await Ban.IP('192.168.1.0/24', {
reason: 'Spam network'
});
await Ban.ASN('AS54115', {
reason: 'Datacenter abuse',
durationMinutes: 1440
});
const result = await Ban.Check('ip', '192.168.1.100');
if (result.banned) {
console.log('IP is banned:', result.database?.reason);
}
await Ban.Remove('ip', '192.168.1.100');
const bans = await Ban.List(20);
const stats = await Ban.Stats();Ban 시스템을 쉽게 관리할 수 있는 CLI 도구를 제공합니다:
bun scripts/ban-test.ts ban-ip 192.168.1.0/24 "Spam network" 60
bun scripts/ban-test.ts ban-asn AS54115 "Datacenter abuse"
bun scripts/ban-test.ts check ip 192.168.1.100
bun scripts/ban-test.ts list
bun scripts/ban-test.ts stats자세한 내용은 Ban 시스템 가이드를 참고하세요.
프레임워크는 Redis(빠른 인메모리 캐싱)와 PostgreSQL(영구 저장소)을 함께 사용합니다.
- KanadiContext
- KanadiBundleSession
- KanadiValidatorSession
- KanadiUser
- KanadiDevice
- KanadiHistory
- Redis 모델과 동일하며, 적절한 관계 설정 포함
데이터는 주기적으로 Redis에서 PostgreSQL로 동기화됩니다.
자세한 사용법은 한국어 문서를 참고하세요:
- 시작하기: 설치 및 기본 설정
- 커스텀 Validator 만들기: Validator 제작 가이드
- Ban 시스템: 차단 시스템 완벽 가이드
완전한 예제는 examples/ 디렉토리를 참고하세요:
- kanadi.gateway.ts: 전체 gateway 구현
- validators/browser.validator.ts: 커스텀 브라우저 검증 예제
- scripts/ban-test.ts: Ban 시스템 CLI 도구
- scripts/ban-cron.ts: 자동 Ban 정리 스크립트
A flexible and extensible CAPTCHA framework that supports multiple validation layers. Unlike traditional CAPTCHAs, Kanadi requires completing all challenges in a bundle before verification is complete.
- Multi-Layer Validation: Chain multiple validators together in a bundle
- Custom Validators: Create your own validators with the
@Validatordecorator - Built-in Validators: Includes Proof of Work (PoW) and browser validation
- NestJS Integration: Seamlessly integrates with NestJS applications
- Database Support: Redis and PostgreSQL support for session management
- Flexible Architecture: Modular design allows for easy customization
npm install kanadi
# or
bun add kanadiSee the Korean documentation above for detailed examples.
See the examples/ directory for complete working examples.
MIT
