PortSwigger Academy - Authentication

전세영·2026년 10월 9일

PortSwigger-Academy

목록 보기
2/2

취약점 종류

  • password-based login
  • multi-factor auth
  • other auth

Password-based login

Brute force
(사실상 딕셔너리 기반) 무작위 대입방법.
브루트포스는 강력하지만, N회 실패시 차단 등의 로직을 어떻게 우회할지가 관건이다.

크게보면
1. username enumeration(username 알아내기)
2. 프로텍션 우회
이다.

이 두가지가 충족되어야 Brute Forcing이 가능한데,
대체로 1번은 사실상 쉽게 충족되지만
2번이 조금더 어려운 부분임.

2번을 제대로한다면, (중요해보이는거만 간소하게 기술함)

Rate Limiting + Account Lock을 하는것인데,

Account Lock

  • 실패횟수 초과시 일정시간 잠금. 실패카운트가 늘어나면 잠금시간 추가
  • 잠금중엔 비밀번호가 맞든 틀리든 동일 응답
  • 영구잠금은 피함

IP Ban

  • IP + 계정 + 디바이스/세션 단위 동시제한
  • 단순 고정횟수가 아닌 점진적 지연/ 지수백오프
  • 헤더(X-Forwarded-For)를 신뢰하지않고 L4 IP를 신뢰( or CDN에서 제공하는 헤더만 신뢰)

하지만 이렇게 잘 구현한다해도,
프록시기반 저속 Credential Stuffing 공격은 가능해 보임

대형서비스(20~30%)는 매우잘막아뒀고,
기본적으로 잘해뒀지만 허점이 있는사이트(40~50%)는

  • 유효계정에만 잠금, 성공시 카운트 리셋, X-Forwarded-For 신뢰, 점진적 지연 없음 등의 결함이 존재한다함.
    프로텍션이 사실상 매우 느슨한곳(20~30%)도 존재

Username Enumeration

존재하는 username을 알아낼수있도록 하는 취약점.

우회방법

  • 회원가입 시 username 중복검사 기능으로 username 취득
  • 로그인 시, 존재하는 username에 대해 미묘하게 다른 응답
  • 에러문구 오타
  • response 차이
    • 존재하는 username은 응답길이가 다름
    • HTML숨은필드, Set-Cookie 유무
    • 존재하는 아이디만 X-Account-Status: active, WWW-Authenticate 헤더 추가
    • 둘다 상태코드는 200인데 JSON 키 순서가 다름
    • 응답시간 차이(timing. 존재하는 id만 응답시간이 수십 ms 느림)
  • 존재 계정에만 "너무 많은 시도" account locking이 존재

등이 존재함.

추가적으로는

  • 비밀번호 재설정 기능 ("해당 이메일로 재설정 링크를 보냈습니다" vs "존재하지 않는 계정입니다."))
    • 응답시간/길이/상태코드 차이
  • 공개 페이지 (/users/{username}, /@{username}, /profile/{id} 등에서 존재하는 유저는 200, 없으면 404)
    • API에서도 같은 패턴

사실상 구조적으로 위 취약점들에서 완전히 자유롭기가 어려움.
그래서 보통 프로텍션이라는 안전장치를 마련하는데,
주로 Rate limiting(Account Lock, IP Ban) / Captcha 이며,
이는 취약점 2에서 다룸

취약점 1.1. 다른응답 - 에러문구 취약점

username을 알아내기 위해, 회원가입으로 중복검사를 하면 된다.

LAB은
로그인시 "존재하지않는 username입니다." 식으로 알려주는 곳에대한 취약점이지만 이런 사이트가 요즘 거의 없어서..
Burp Suite기초사용법 연습하는 의미가 더크다. Intruder 써서 무작위대입해보고, 응답 Length가 다른것을 필터해서 보면된다.

1.2. 미묘하게 다른 응답 - 에러문구 오타

위와 같으나,
비번을 틀리든 없는 유저를입력하든
"username, password가 일치하지 않습니다."
의 메시지가 나오지만,
두 경우에 따라 오타로 공백(" ")만큼 차이가 나는 등 Response에 미묘한 차이가 있는 경우.

에러메시지만 가져오는방법은
우측탭 Setting - Grep Match - "에러메시지입력"
하면 그 문장이 Response에 몇번나왔는지 보여준다.
0인걸 찾아서 보면 해결

사실 에러메시지 오타보단

  • 응답길이, 숨은필드, Set-Cookie유무
  • 응답이 수십 ms느림
  • 둘다 상태코드는 200인데 JSON 키 순서가 다름

등으로 구분되는 취약점이 흔하다고 함.
Response 차이를 바이트단위로 보는 습관을 들이면 좋다함

1.3. 미묘하게 다른 응답 - response timing

비밀번호를 100자이상으로해서 username을 무작위대입하면 유난히 1초를넘기는 응답을 확인하면 존재하는 username.

IP 블로킹 프로텍션이 걸려있으므로,
X-Forwarded-For의 아이피를 스푸핑해 우회해줘야함

되는 이유:
존재하지 않는 username은 즉시 응답이오지만,
존재하는 username은 비밀번호 조회를 위해 시간이 걸리는 경우가 많다함.

방어: django, spring security 등에선 존재하지않는 유저도 해시검증을 넣어서 둘의 지연시간을 비슷하게 맞춰서 방어함

단, Spring Security없이 Spring만 써서 로그인구현을 한 사이트엔 충분히 유효한 취약점

Spring만으로 직접 짠 로그인 사이트에서 bycrypt만 썼다면 속도차이가 나서 취약함.
SHA256을썼다면 응답이 빠르기때문에, 여기엔 안전하지만 password를 브루트포스하는 시간이 빨라지는 취약점이 발생

팁1 : 해시가 느린이유. 해시속도는 마이크로초 수준이지만, 빠른 해시는 공격에 취약하기때문에(공격이 빨라짐) bcrypt등의 해시는 고의적으로느리게 만들었다. (연산반복)

프로텍션 우회

기본적으로

  • 로그인 실패를 많이한 아이디 차단 (아이디 단위 실패횟수 제한)
  • 로그인 실패를 많이한 IP 차단

두 방식이 있다.

우회방법

IP 차단은,

  • X-Forwarded-For / X-Real-IP 등 헤더를 아이피 스푸핑해 우회
  • 로그인 성공시 실패횟수를 초기화하는 결함
  • 기타 : 프록시/Tor/VPN 로테이션, IPv6 활용, 클라우드 IP대역 우회 등

아이디차단방식은,

  • Password Spraying : 자주쓰이는 비번(3개=차단횟수에맞춤)을 모든아이디에 시도 (적어도 몇개 얻어걸림)
  • Credential Stuffing : 이미 유출된 username:password 대용량 dictionary를 그대로 대입

취약점 2.1. IP ban - X-Forwarded-For 헤더 스푸핑

로그인 실패를 해도, 로그인성공시 실패횟수를 초기화하는 취약점.

LAB(비밀번호 알아내기):
정상로그인(wiener), 공격시도(carlos)를 무한반복하고, 302응답 온 carlos를 확인하면 된다.

취약점 2.2 계정 락 -

profile
가치를 빠르고 안전하게 전달하는 개발을 하고 싶습니다.

0개의 댓글