Notice
Recent Posts
Recent Comments
Link
250x250
반응형
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- 랜섬웨어
- 시험
- go
- 정보보안
- cypher
- 정보보안기사
- graph
- SQLD
- 사이버 보안
- 보안 분석
- GraphDB
- security
- 사이버보안
- 데이터모델링
- 자격증
- 그래프 데이터베이스
- concurrency
- Database
- 해킹
- 공부
- 보안솔루션
- Golang
- 그래프데이터베이스
- 보안
- neo4j성능
- 위협 탐지
- IT보안
- 정리
- 프로그래밍
- Neo4j
Archives
- Today
- Total
Jamie the programmer
Go에서 Rate Limiting으로 공격 방어하기: Token Bucket vs Leaky Bucket 본문
programming/golang
Go에서 Rate Limiting으로 공격 방어하기: Token Bucket vs Leaky Bucket
jamie91 2025. 3. 10. 11:10
Contents
접기
반응형

대규모 트래픽을 다루는 서버나 API에서는 Rate Limiting(속도 제한)이 매우 중요하다.
보안 관점에서도, 무차별 암호 대입 공격(Brute Force)이나 Dos/DDoS 공격과 같은 악의적 트래픽을 효과적으로 제한하기 위해서는 Rate Limiting이 필수적이다.
또한, 계정 도용 방지, API Key 남용 방지, 자원(네트워크, CPU, DB 등) 보호 등 다양한 측면에서 보안 강화를 기대할 수 있다.
Go 언어에서는 표준 라이브러리에 포함된 확장 패키지 golang.org/x/time/rate와, 오픈소스로 제공되는 go.uber.org/ratelimit 라이브러리가 대표적이다. 이 글에서는 이 두 라이브러리가 구현하고 있는 대표적인 알고리즘인 Token Bucket과 Leaky Bucket에 대해 간단히 살펴보며, 보안적으로 어떤 이점을 얻을 수 있는지 알아보자.
1. Go에서의 Rate Limit
1.1 golang.org/x/time/rate
- Token Bucket 알고리즘을 기반으로 구현된 Rate Limiting 라이브러리
- API 요청 횟수를 초당 몇 건으로 제한하고, 동시에 몇 건의 버스트(순간적인 폭주)를 허용할지 쉽게 설정 가능
- 보안 측면: 공격자가 짧은 시간에 대량의 요청을 보내도, Token Bucket에 의해 초당 처리 가능한 요청 수가 제한되므로 Brute Force, Dos 공격을 어느 정도 방어 가능
1.2 go.uber.org/ratelimit
- Leaky Bucket 알고리즘을 기반으로 구현된 Rate Limiting 라이브러리
- 물이 샌다고 가정한 양동이(버킷)에 트래픽을 넣고 일정 속도로 빠져나가도록 하여, 갑작스러운 대규모 트래픽(공격 트래픽 포함)을 제한
- 보안 측면: 안정적으로 일정 속도로만 요청을 처리하므로, 분산된 Dos/DDoS 공격에도 서버가 급격히 과부하되지 않도록 보호
참고
2. Token Bucket Algorithm
Token Bucket 알고리즘은 시간에 따라 일정 속도로 토큰을 충전해두고, 요청 시 토큰을 소모하는 방식으로 동작한다. 아래 그림처럼, 일정 간격으로 버킷에 토큰이 추가되고, 요청이 들어오면 토큰을 하나씩 사용한다. 버킷이 비어 있으면 토큰이 재충전될 때까지 대기하거나, 요청이 거부된다.

Token Bucket의 핵심 개념
- 토큰 버킷(Token Bucket)
- 버킷의 깊이(용량)를 b라고 할 때, 버킷은 최대 b개의 토큰을 보유
- 버킷이 가득 차 있을 때 새 토큰이 들어오면 버려짐
- 토큰 충전 속도(r)
- 1초에 r개씩 토큰을 충전한다고 가정
- 예: 초당 5개 토큰 = 초당 5회 요청 허용
- 요청 처리
- 리소스에 접근하려면 토큰 1개가 필요
- 버킷에 남아 있는 토큰이 있으면 즉시 요청을 처리(토큰 제거)
- 버킷이 비어 있으면 요청을 대기열에 두거나 거부
- 버스트 처리
- 짧은 시간에 몰리는 트래픽(버스트)을 어느 정도 흡수 가능
- 버킷에 토큰이 남아 있으면, 순간적으로 많은 요청이 와도 빠르게 처리
보안적 이점
- Brute Force 방어: 초당 N회 이상의 시도가 불가능하므로, 대규모 비밀번호 시도 등 무차별 대입 공격 완화
- Dos/DDoS 완화: 순간 폭주 트래픽을 제한하여 서버가 급격히 다운되는 상황 방지
- 자원 보호: 토큰이 없으면 더 이상 요청을 허용하지 않으므로, 데이터베이스나 내부 서비스 과부하를 줄임
3. Leaky Bucket Algorithm
Token Bucket과 자주 비교되는 알고리즘으로, go.uber.org/ratelimit가 채택한 Leaky Bucket 방식이 있다.
- Leaky Bucket은 버킷에 물(요청)이 담기면 일정한 속도로 물이 빠져나가는 구조를 가정
- Token Bucket이 “토큰이 충전되어야 요청을 처리할 수 있음”이라면, Leaky Bucket은 “들어오는 요청(물)은 일단 버킷에 쌓이고, 일정 속도로 빠져나가므로 그 속도를 초과하면 버킷이 넘쳐 요청이 버려짐”에 가까움
보안적 이점
- 일정 처리 속도 보장: 트래픽이 한꺼번에 몰려와도 일정 속도로만 빠져나가므로, 서버 자원이 고갈되지 않도록 방어
- 분산 공격 방어: 대규모로 분산된 Dos/DDoS 공격에도, 버킷이 제한된 양만 처리하고 나머지는 버려서 시스템 다운을 예방
4. 간단 예시: golang.org/x/time/rate로 Token Bucket 구현
package main
import (
"fmt"
"time"
"golang.org/x/time/rate"
)
func main() {
// 초당 2개 요청, 버스트는 3개까지 허용
limiter := rate.NewLimiter(2, 3)
for i := 1; i <= 10; i++ {
// Wait는 토큰이 생길 때까지 대기 (Context 없이 사용하면 Background context)
err := limiter.Wait(nil)
if err != nil {
fmt.Println("Error:", err)
continue
}
fmt.Printf("Request #%d allowed at %v\\\\n", i, time.Now())
}
}
- rate.NewLimiter(r, b)에서 r은 초당 토큰 충전 개수, b는 버킷 용량(버스트 허용량)을 의미
- Wait() 함수는 토큰이 없으면 자동으로 대기 후 처리
- 보안적으로도, 초당 요청 횟수를 엄격히 제한하므로 API Key 오남용이나 대규모 트래픽 유입 시에도 서버가 급격히 과부하되지 않는다.
5. Rate Limiting 구현 시 주의사항
- 정확한 시간 측정
- OS 스케줄링이나 고루틴 스위칭으로 인해 완벽히 초당 N회 처리만 보장하기는 어려울 수 있다.
- 약간의 오차 보정 또는 버퍼를 두어 운영하는 것이 안정적이다.
- 오류(429 Too Many Requests) 처리
- 클라이언트가 429 오류를 받을 때 재시도 정책을 안내하거나, 쿨다운(cooldown) 시간을 명시하는 등 사용자 경험도 고려
- 추가적인 보안 로직
- Rate Limiting만으로 모든 공격을 차단할 수는 없다.
- IP 블랙리스트, WAF(Web Application Firewall), 모니터링 & 로깅, 알림 시스템 등과 연계해 다층 보안을 구축하는 것이 좋다.
6. 마무리
- Rate Limiting은 서버 안정성과 보안을 위해 필수적인 기법이다.
- Go 언어에서는 표준 라이브러리 확장 모듈인 golang.org/x/time/rate로 Token Bucket 방식을 간단히 적용할 수 있으며, go.uber.org/ratelimit를 통해 Leaky Bucket 알고리즘을 활용할 수도 있다.
- Brute Force나 Dos/DDoS 공격, API Key 남용 등을 막기 위해서는 Rate Limiting이 강력한 1차 방어 수단이 된다.
- 실제 운영 환경에서는 트래픽 패턴, 서버 자원, 사용자 요구사항 등을 종합적으로 고려해 버킷 크기(b), 토큰 충전 속도(r) 등의 파라미터를 설정해야 하며, 추가 보안 레이어와 함께 사용하면 더 효과적이다.
참고 자료
728x90
반응형
'programming > golang' 카테고리의 다른 글
Go 개발 환경 정복하기: 패키지, 모듈, 그리고 워크스페이스 (0) | 2025.03.10 |
---|---|
Go에서 Throttling과 Debouncing? 요청은 줄이고 효율은 높이자! (0) | 2025.03.10 |
고루틴도 편히 쉬어야 한다! Go에서 Graceful Shutdown 구현하기 (0) | 2025.03.10 |
Go 언어, 이렇게 쓰면 GOAT 된다 - 실전 꿀팁 12개! (0) | 2025.03.10 |
Go 코드에서 UML 다이어그램 뽑아내기 – 개발자 생산성 200% UP! (0) | 2025.03.07 |