회원가입 | 고객센터 |
DESIGNONEX
DesignOneX CMS
로그인 회원가입
고객센터

DX Security — Rate Limit Bypass 보안 플러그인

D DX관리자
2026.09.04 01:50(수정됨) 7 0



DX Security — Rate Limit Bypass 방어 v1.0.0 안내서

PHP 5.6+ · IIS / Apache / Nginx 완전 호환 코어 Secure::rateLimit() 완전 재사용 코어 수정 없음 — 훅으로만 동작



목차

  1. Rate Limit Bypass란 무엇인가
  2. DXCMS 코어의 현재 방어 수준
  3. 이 플러그인의 역할
  4. 설치 방법
  5. 방어층 상세 설명
  6. Endpoint 정책 Registry
  7. 보안 로그 읽는 법
  8. 보안 강점 요약
  9. 개발자 API 가이드


1. Rate Limit Bypass란 무엇인가

공격자가 Rate Limit의 식별 기준(IP, Session 등)을 변경하거나 요청 경로를 바꿔 제한을 무력화하는 공격입니다.

우회 방법:

IP 변경:
  IP A → 100회 → 차단
  IP B → 100회 → 차단 우회
  IP C → 100회 → 차단 우회

Session 변경:
  Cookie 삭제 → 새 Session → Rate Limit 초기화

Endpoint 변경:
  /api/login 차단됨 → /api/auth/login 시도

XFF 조작:
  X-Forwarded-For: 1.1.1.1 → 2.2.2.2 → 3.3.3.3
  → IP Rate Limit 우회


핵심 원칙

Rate Limit을 IP 하나에만 묶지 않는다.

올바른 구조:
  Canonical IP  (14번 Proxy Trust 검증 결과)
      +
  Session
      +
  Account
      +
  Endpoint
      +
  Global


2. DXCMS 코어의 현재 방어 수준

코어 rateLimit() 구현

public function rateLimit($key, $limit = 30, $window = 60)
{
    $ip = $this->clientIp();  // 14번 Proxy Trust 검증된 IP 사용

    // Redis가 있으면 원자적 INCR (Race Condition 방어)
    if (self::$redis !== null) {
        $slot  = floor(time() / $window);
        $sKey  = 'rl:' . $key . ':' . $slot;
        $count = self::$redis->incr($sKey);
        if ($count === 1) self::$redis->expire($sKey, $window + 5);
        return $count <= $limit;
    }

    // Redis 없으면 파일 기반 폴백
    return $this->fileRateLimit($key, $ip, $limit, $window);
}


코어 평가

항목 방어 평가
Redis 원자적 INCR Race Condition 방어
파일 기반 폴백 공유호스팅 호환
Canonical IP 사용 clientIp() = Proxy Trust 검증
다층 Key 없음 IP 단일 계층만
Endpoint 정책 없음 개별 정의 필요
429/Retry-After 없음 표준 응답 없음
Global Rate Limit 없음 Endpoint 변경 우회 가능


3. 이 플러그인의 역할

코어 Secure::rateLimit()을 완전히 재사용합니다. 저장소(Redis/파일)를 그대로 공유하면서 다층 Key와 정책 Registry를 추가합니다.



4. 설치 방법

(DXCMS 루트)/
└── plugins/
    └── dx-security-ratelimit/
        ├── manifest.php
        └── plugin.php
관리자 → 플러그인 → dx-security-ratelimit → 활성화


5. 방어층 상세 설명


RL1. IP + Session + Account + Global 다층 Rate Limit

단일 Key(IP만) 방어에서 4계층 방어로 강화합니다.

요청 들어옴
    ↓
[1] Global Rate Limit (Endpoint 변경 우회 방어)
    ↓ 통과
[2] IP Rate Limit (코어와 동일한 Canonical IP 사용)
    ↓ 통과
[3] Session Rate Limit (IP 변경 우회 방어)
    ↓ 통과
[4] Account Rate Limit (Session 변경 우회 방어, 로그인 시)
    ↓ 통과
비즈니스 로직 실행

각 계층에서 초과 시 즉시 429 반환.



RL2. Endpoint별 정책 Registry

각 엔드포인트마다 독립적인 Rate Limit 정책을 선언합니다.

login:
  IP — 6015회
  Session — 6010회
  Account — 3005Global60300password_reset:
  IP — 6005회
  Session — 6003회
  Account — 36003회 (계정당 1시간에 3회)
  Global6030


RL3. Rate Limit Bypass 탐지 로그

Rate Limit 초과 시 탐지 이벤트를 기록합니다.



RL4. 표준 429 / Retry-After 응답

코어는 false만 반환합니다. 이 플러그인은 표준 HTTP 응답을 제공합니다.

HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Policy: login

일반 브라우저:
  <h1>429 Too Many Requests</h1>

AJAX/JSON 요청:
  {
    "success": false,
    "message": "요청이 너무 많습니다. 60초 후 다시 시도하세요.",
    "code": "RATE_LIMITED",
    "retry_after": 60
  }


RL5. Global POST Rate Limit

Endpoint를 계속 변경하는 공격을 방어합니다.

공격:
  /api/login → 차단됨
  /api/auth  → 차단됨
  /api/member → 차단됨
  ...
  → 각 Endpoint는 제한 미도달

방어:
  IP별 모든 POST 요청 — 60초 100회
  → Endpoint 변경해도 상위 제한 적용


6. Endpoint 정책 Registry

Endpoint IP 제한 Session 제한 Account 제한 Global 제한
login 15회/60초 10회/60초 5회/300초 300회/60초
admin_login 5회/300초 3회/300초 3회/600초 20회/60초
register 5회/300초 3회/300초 - 50회/60초
password_reset 5회/600초 3회/600초 3회/3600초 30회/60초
post_write 10회/60초 8회/60초 5회/60초 -
comment 30회/60초 20회/60초 15회/60초 -
upload 20회/60초 15회/60초 10회/60초 -
og_fetch 20회/60초 15회/60초 - -
api_default 60회/60초 50회/60초 40회/60초 -


7. 보안 로그 읽는 법

이벤트 타입

타입 의미
RL:EXCEEDED Rate Limit 초과 — 429 반환
RL:GLOBAL_POST_EXCEEDED Global POST Rate Limit 초과
RL:BYPASS_ATTEMPT 코어 rateLimit false 반환 탐지
RL:PLUGIN_RL_IP 플러그인 API — IP 초과
RL:PLUGIN_RL_SESSION 플러그인 API — Session 초과
RL:PLUGIN_RL_ACCOUNT 플러그인 API — Account 초과


로그 예시

# 로그인 IP Rate Limit 초과
[2026-09-03 09:00:01][RL:EXCEEDED][IP:45.33.x.x][...][UID:0][POST /auth/login]
endpoint=login layer=IP retry_after=60

# Session 변경 우회 시도 차단
[2026-09-03 14:22:10][RL:EXCEEDED][IP:58.29.x.x][...][UID:0][POST /auth/login]
endpoint=login layer=SESSION retry_after=60

# Global POST 초과 (Endpoint 변경 우회)
[2026-09-03 16:45:03][RL:GLOBAL_POST_EXCEEDED][IP:103.21.x.x][...][UID:0][POST /api/other]
uri=/api/other


8. 보안 강점 요약

우회 시도 결과 방어 레이어
IP 변경 Session/Account 계층에서 차단 RL1
Session 삭제/변경 IP/Account 계층에서 차단 RL1
Account 변경 (다계정) IP/Session 계층에서 차단 RL1
Endpoint 변경 Global POST Rate Limit RL5
XFF 조작 코어 Canonical IP 사용 → 동일 Key 코어+14번
비밀번호 재설정 반복 계정당 1시간 3회 RL2
정상 사용자 정책 내에서 정상 처리


9. 개발자 API 가이드

플러그인 엔드포인트 Rate Limit

// Registry 정책 사용
if (!dx_rate_limit('login')) {
    dx_rate_limit_deny(60, 'login');
}

// 직접 정책 정의
if (!dx_rate_limit('my_plugin_vote', array(
    'ip_limit' => 3, 'ip_window' => 60,
    'acct_limit' => 1, 'acct_window' => 86400,
))) {
    dx_rate_limit_deny(60, 'vote');
}


정책 Registry에 추가

// 플러그인 활성화 시 정책 등록
dx_rl_policy_add('my_plugin_api', array(
    'ip_limit'    => 10,  'ip_window'    => 60,
    'sess_limit'  => 8,   'sess_window'  => 60,
    'acct_limit'  => 5,   'acct_window'  => 60,
    'global_limit'=> 100, 'global_window'=> 60,
));

// 이후 사용
if (!dx_rate_limit('my_plugin_api')) {
    dx_rate_limit_deny(60, 'my_plugin_api');
}


간단한 단일 계층 사용

// 빠른 단일 IP Rate Limit (코어 직접 사용)
$allowed = Secure::getInstance()->rateLimit('my_simple_action', 10, 60);
if (!$allowed) {
    http_response_code(429);
    exit;
}

DX Security — Rate Limit Bypass 방어 v1.0.0 — DesignOneX https://designonex.com
 

라이선스

디자인원엑스 라이선스 참고
https://designonex.com/notice/view/1787577858493247

 

첨부파일 1개 회원전용

댓글0

로그인 후 댓글을 작성할 수 있습니다.
Plugin 53
45
전체 회원
1,391
전체 게시글
2,748
전체 댓글
80
오늘 방문
53,598
전체 방문
1
현재 접속
인기글 7일 이내
최신글
최신댓글
내 플레이리스트
플레이리스트가 비어있습니다
스튜디오 게시판에서
플레이리스트에 담기 버튼을
눌러보세요
목록
목록