HTTP 완벽 가이드 - HTTP 기본 인증 (Basic Authentication)

송현진·2025년 9월 16일

Network

목록 보기
14/16

HTTP는 본질적으로 무상태(stateless) 프로토콜이기 때문에 어떤 사용자가 어떤 자원에 접근할 수 있는지 서버가 알 수 없다. 따라서 인증(Authentication) 메커니즘이 필요하다. 그 중 가장 단순하면서도 초창기부터 정의된 방식이 바로 기본 인증(Basic Authentication)이다. 기본 인증은 누구인지 증명하는 것에만 집중한다. (인가/권한 부여는 그 이후 단계)

동작 과정

기본 인증은 사실상 HTTP 헤더 교환만으로 작동한다. 브라우저나 클라이언트 라이브러리가 이를 자동 처리하기 때문에 눈에 잘 안 보이지만, 패킷을 보면 단순하다.

1. 클라이언트가 보호된 자원 요청

GET /private/data HTTP/1.1
Host: www.example.com

2. 서버가 인증 요구
서버는 이 자원이 보호되어 있다는 뜻으로 401 Unauthorized 응답을 반환한다.
함께 WWW-Authenticate 헤더를 내려 클라이언트에게 어떤 인증 방식을 사용할지 알린다.

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Private Area"

realm은 인증 구역(보호영역)을 나타내는 문자열이다. 사용자가 어떤 자격 증명을 입력해야 하는지 브라우저에 표시하는 용도로 쓰인다.

3. 클라이언트가 자격 증명 전송
사용자가 브라우저에 아이디/비밀번호를 입력하면 클라이언트는 username:passwordBase64 인코딩Authorization 헤더로 보낸다.

GET /private/data HTTP/1.1
Host: www.example.com
Authorization: Basic dXNlcjpwYXNzd29yZA==

여기서 dXNlcjpwYXNzd29yZA==user:password를 Base64로 인코딩한 문자열이다.

4. 서버가 인증 검증 후 응답
서버가 Authorization 헤더를 확인해 유효하면 정상 응답을 보낸다.

HTTP/1.1 200 OK
Content-Type: text/plain

Hello, user!

Base64의 함정

Base64는 암호화가 아니라 단순한 인코딩(문자열 변환)일 뿐이다. username:password를 Base64로 인코딩하면 사람이 직접 읽기 어렵게 보일 뿐 누구나 디코딩해서 원래 문자열을 복원할 수 있다. 즉 네트워크 상에서 Authorization 헤더가 노출되면 평문 자격 증명이 그대로 유출되는 것과 다름없다. 이 때문에 Basic Authentication을 사용할 때는 항상 TLS(HTTPS)를 적용해야 하며 HTTPS가 아닌 채널에서 절대 쓰지 않아야 한다. 또한 Base64로 인코딩된 자격 증명은 브라우저 로그, 서버 접근 로그, 프락시 로그에 그대로 남을 수 있으므로 로그 수집 및 보관정책에서도 특별한 주의가 필요하다.

캐싱과 인증

프락시나 캐시 서버는 인증된 리소스의 응답을 캐시할 수 있는데 이때 캐시 키로 사용되는 요소들(요청 경로, 쿼리, 헤더 등)에 Authorization 헤더나 WWW-Authenticaterealm 정보가 반영되지 않으면 다른 사용자가 잘못된 응답을 보게 될 위험이 있다. 특히 공용 프락시나 공유 네트워크 환경에서는 인증정보가 포함된 응답을 캐시하면 민감한 데이터가 의도치 않게 노출될 수 있다. 따라서 보호된 리소스의 경우 적절한 Cache-Control: no-store, no-cache 또는 Vary 헤더(Vary: Authorization)를 설정해 캐시 오염을 방지해야 한다. 내부적으로는 프락시/캐시 계층에서 인증별로 분리된 캐시 영역을 유지하거나 인증 응답을 전혀 캐시하지 않는 정책을 권장한다.

한계와 문제점

  1. 보안 취약
    Basic 인증은 자격 증명을 매 요청마다 전송하므로 네트워크에서 가로채기 당하면 계정이 바로 노출된다. Base64가 암호화가 아니라는 점과 결합하면 TLS 미적용 환경에서는 거의 평문 전송과 동일한 취약점을 가진다.

  2. 자격 증명 노출
    브라우저가 한 번 인증 정보를 받으면 동일한 도메인/realm에 대해 자동으로 Authorization 헤더를 계속 붙여 보낸다. 이로 인해 브라우저의 개발자 도구, 확장 프로그램, 또는 중간 로깅 시스템에 자격 증명이 남을 가능성이 커진다. 또한 공유 기기에서 로그아웃이 곤란해지는 UX/보안 문제가 있다.

  3. 취소 어려움
    사용자가 ‘로그아웃’ 버튼을 눌러도 브라우저는 내부 캐시된 자격 증명을 계속 사용한다. 표준화된 로그아웃 메커니즘이 없어 브라우저를 닫거나 자격 증명을 만료시키는 서버 측 조치를 병행해야 하는 등 실무에서 불편함이 크다.

  4. 서버 부하
    매 요청마다 Authorization 헤더를 확인하고 필요 시 외부 인증 저장소(예: DB, LDAP)와 조회를 반복해야 하므로 트래픽이 많은 환경에서는 인증 검증이 병목이 될 수 있다. 세션이나 토큰 기반 방식처럼 검증 비용을 줄이는 캐싱/토큰 검증 전략을 도입하는 것이 성능상 유리하다.

대안

실무에서는 Basic 인증 대신 더 안전하고 유연한 방식을 사용한다. 예를 들어 세션 기반 인증은 서버가 세션 ID를 발급해 클라이언트는 쿠키만 전송하도록 하여 자격 증명 재전송을 피할 수 있고 OAuth2JWT 같은 토큰 기반 인증은 액세스 토큰을 통해 권한을 위임하고 만료/갱신 전략을 적용할 수 있어 보안과 확장성 면에서 유리하다. Digest 인증은 Basic보다 안전하지만 구현 및 운영이 복잡하고 현대적 요구사항(모바일, CORS, SPA)에서는 한계가 있어 잘 쓰이지 않는다. 따라서 내부 API나 간단한 테스트 환경을 제외하고는 HTTPS + 토큰(또는 세션) 기반 인증을 기본으로 설계하는 것이 좋다.

[클라이언트] ---- GET ----> [서버]
           <--- 401 + WWW-Authenticate (Basic realm)
[클라이언트] ---- GET + Authorization: Basic ... ---->
           <--- 200 OK + 자원

📝 배운점

HTTP 기본 인증은 단순히 헤더 교환만으로 동작하기 때문에 구현 자체는 매우 간단하지만 보안적인 한계가 명확했다. Base64가 암호화가 아니라는 점을 직접 확인하면서 “안전한 채널 위에서만 의미가 있다”는 사실을 깨달았다. 또한 브라우저가 자격 증명을 내부적으로 캐싱해 계속 사용하는 방식 덕분에 UX는 간단해지지만 반대로 로그아웃이 제대로 되지 않는 문제가 있다는 것도 알 수 있었다. 결국 Basic 인증은 학습이나 내부 테스트 환경에서는 충분히 유용하지만 실제 서비스에서는 HTTPS를 반드시 전제로 하고도 세션/토큰 기반 인증으로 발전시키는 것이 필수라는 점을 배웠다. 특히 Cache-Control, Vary: Authorization` 같은 헤더를 통해 캐시 안전성을 확보해야 한다는 점은 실무적인 디테일로서 중요한 교훈이었다.

profile
개발자가 되고 싶은 취준생

0개의 댓글