【제14회】 관리자 로그인을 지키다! 비밀번호 시도 제한과 15분간 잠금(Lockout)을 통한 무차별 대입 공격 방어
요약
본 글은 웹사이트의 관리자 대시보드를 무차별 대입 공격(Brute Force Attack)으로부터 보호하는 보안 메커니즘 설계 과정을 다룹니다. 15분 이내 실패 5회 시도 제한과 IP 기반 일시 잠금(Lockout)을 도입하여 사이트 전체를 지키는 방법을 설명합니다.
핵심 포인트
- 관리자 대시보드는 사이트의 핵심 급소이므로 강력한 보호가 필수입니다.
- 15분 동안 최대 5회의 실패 허용 후, IP 기반으로 접근을 물리적으로 차단합니다.
- 로그인 시도 추적은 고정된 날짜가 아닌 '현재 시각으로부터 과거 900초'를 기준으로 합니다.
- 비밀번호 비교 시 시간차 공격 방지를 위해 `hash_equals()` 같은 함수를 사용해야 합니다.
"초당 50회의 속도로 'password', 'admin', '123456' 등을 시도하는 로그인 요청이 밀려들고 있었다"
레와(令和) 시대에 직접 만든 2채널 스타일 게시판 "츠우바이 채널(つゔぁいちゃんねる, 2ch.biz)" 개발 비화의 제14탄입니다. 이번에는 사이트 전체의 모든 권한을 쥐고 있는 "관리자 대시보드(Admin Dashboard)"를 사전 공격 및 무차별 대입 공격(ブルートフォースアタック)으로부터 보호하기 위한 로그인 시도 제한과 계정 일시 잠금 메커니즘 설계에 대해 설명합니다.
제2회에서 설명했듯이, 츠우바이 채널에는 게시판 생성/삭제, 전체 스레드 모더레이션, IP BAN을 한 번에 담당하는 강력한 **"관리자 대시보드(Admin Console)"**가 존재합니다.
이 관리 화면은 운영의 핵심이지만, 역설적으로 **"여기가 뚫리면 사이트 전체를 순식간에 소멸시킬 수 있는 최대 급소"**이기도 합니다.
만약 공격자에게 관리자 비밀번호가 노출될 경우:
- 모든 카테고리/모든 게시판/모든 스레드의 일괄 완전 삭제
- 악의적인 피싱 사이트나 멀웨어 배포 사이트로 강제 리다이렉트 스크립트 삽입
- 이용자의 IP 주소 및 신고 로그 유출
등, 되돌릴 수 없는 대참사가 발생합니다.
그리고 무서운 점은, 인터넷상의 봇들은 새로운 도메인이 개통되는 순간부터 /admin,
/admin.html,
/login
같은 경로를 기계적으로 스캔하며, 사전에 등록된 수만 가지의 비밀번호를 초당 수십 회의 엄청난 속도로 무차별 대입을 시도한다는 것입니다.
이 공격을 확실하게 잠재우기 위해, 개발 초기(2026년 8월 18일)에 **"로그인 시도 제한(ブルートフォース防御エンジン)"**을 도입했습니다.
일반적인 웹 서비스에서는 '비밀번호가 틀립니다'라고만 응답하는 경우가 많지만, 보안과 정상적인 관리자의 편의성을 양립시키기 위해 다음과 같은 엄격한 규칙을 수립했습니다.
- 실패 허용 횟수: 직전 15분(900초) 이내에 최대 5회.
- 남은 시도 횟수 가시화: 잘못된 비밀번호를 입력했을 때, '앞으로 몇 번 더 실패하면 일시 잠금됩니다'라는 경고를 명시합니다.
- 15분간의 일시 잠금(Temporary Lockout): 5회 연속으로 틀릴 경우, 해당 IP 주소로부터의 관리자 로그인을 15분 동안 물리적으로 차단합니다(비밀번호 검증 처리조차 수행하지 않음).
- 성공 시 즉시 리셋: 올바른 비밀번호로 로그인에 성공한 순간, 과거 실패 기록을 원자적(atomic)으로 삭제하고 카운트를 0으로 복구합니다.
공격자의 시도 횟수와 타임스탬프를 추적하기 위한 전용 테이블을 신설했습니다.
CREATE TABLE IF NOT EXISTS admin_login_attempts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip VARCHAR(45) NOT NULL,
...
고정된 '0시~24시'와 같은 집계가 아니라, **"현재 시각으로부터 과거 900초(15분간) 사이에 실패가 몇 건 발생했는지"**를 동적으로 카운트합니다. 이를 통해 날짜가 바뀌는 등의 공격도 빈틈없이 포착할 수 있습니다.
public function attemptAdminLogin($inputPassword, $clientIp) {
$now = time();
$windowSeconds = 900; // 15분간
...
}
본 기능 구현에 있어 코드의 세부적인 부분에도 보안 대책을 마련했습니다.
문자열의 단순 비교($a === $b)
를 사용하면, 시작부터 한 글자씩 비교되기 때문에 '첫 글자가 맞을 때'와 '첫 글자부터 틀릴 때' 사이에 응답 시간에서 나노초 단위의 차이가 발생합니다. 고도화된 해커는 이 미세한 시간차로부터 비밀번호를 추측해냅니다.
PHP의 password_verify()나 hash_equals()
을 사용함으로써, 결과에 관계없이 항상 일정한 시간에 비교를 완료하여 시간차로 인한 정보 유출을 물리적으로 봉쇄했습니다.
잠금 상태인 IP로부터의 요청은, 무거운 비밀번호 해시 계산(Argon2나 bcrypt)을 실행하기 전에 첫 번째 쿼리에서 즉시 차단하는 설계입니다. 이를 통해 공격자가 수만 건의 로그인 요청을 보내와도 서버의 CPU가 과부하로 비명을 지르는 일은 없습니다.
제14회에 걸쳐 게시판의 최고 사령탑을 무차별 대입 공격으로부터 보호하는 **"관리자 무차별 대입 방어 시스템"**에 대해 설명했습니다.
핵심 지점 방어 (5회 제한): 15분 동안 5회 실패 시 일시 잠금(Lockout)을 적용하여, 사전 공격(Dictionary Attack)의 시도 속도를 완전히 차단합니다. -정상 관리자 사용자에 대한 배려: '몇 번 남았는지'를 명확히 표시함으로써, 관리자 본인의 오입력으로 인한 잠금 사고를 미연에 방지합니다. -타이밍 공격과 고부하의 이중 대책: 상수 시간 비교(Constant Time Comparison)와 조기 exit을 통한 서버 자원의 완벽한 방어막을 구축했습니다.
관리자 인증 보안을 강화했습니다.
하지만 웹 위협은 폼에 대한 직접적인 공격만으로는 끝나지 않습니다.
'브라우저의 취약점을 이용하는 XSS(Cross-Site Scripting)나, 다른 사이트에서 부당하게 삽입되는 클릭 자킹(Clickjacking) 공격' 등이 있습니다.
다음 편에서는 【제15회】CSP, HSTS, X-Frame-Options! XSS·클릭 자킹을 근절하는 보안 헤더 완전 방벽으로 이어집니다!
운영 서비스: https://2ch.biz/
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기