Why We Don't Trust the Database with Authentication

Hacker News · 2026.07.17
Why We Don't Trust the Database with Authentication

데이터베이스를 인증의 최종 권한자로 신뢰하면 안 되는 이유

API를 개발하다 보면 자연스럽게 생기는 암묵적인 가정이 있다. "데이터베이스에 레코드가 존재한다면, 그것은 유효한 것이다." 이 가정은 너무 자연스럽게 코드에 녹아들기 때문에 취약점으로 인식되지 않는 경우가 많다. 하지만 이 설계 철학은 특정 공격 시나리오에서 시스템 전체를 무너뜨리는 치명적인 결함이 된다.

SQL Injection이 인증을 우회하는 구체적인 시나리오

API 키 기반 인증을 구현할 때 가장 흔한 패턴은 다음과 같다.

-- api_keys 테이블 구조
CREATE TABLE api_keys (
    id BIGINT PRIMARY KEY,
    org_id BIGINT NOT NULL,
    key_hash VARCHAR(64) NOT NULL  -- SHA-256 해시 저장
);
  1. 랜덤 시크릿을 생성한다.
  2. SHA-256으로 해싱한다.
  3. api_keys 테이블에 org_id와 함께 해시를 저장한다.
  4. 요청이 들어오면 시크릿을 해싱하여 일치하는 행을 조회한다.

이 방식은 플레인텍스트를 저장하지 않기 때문에 안전해 보인다. 하지만 공격자가 애플리케이션 어딘가에서 SQL Injection 취약점을 발견한다면 이야기가 달라진다. 공격자는 먼저 합법적으로 계정을 만들고 자신의 API 키를 발급받는다. 본인의 키이므로 플레인텍스트 시크릿을 알고 있다. 그 다음, SQL Injection을 통해 단순한 UPDATE 구문으로 피해자의 key_hash를 자신의 key_hash로 덮어쓴다.

-- 공격자가 실행하는 SQL (피해자의 key_hash를 자신의 것으로 교체)
UPDATE api_keys
SET key_hash = '공격자_자신의_해시값'
WHERE org_id = 피해자_org_id;

이후 공격자는 자신의 유효한 키로 피해자의 리소스에 완전히 접근할 수 있다. 해시를 역산할 필요도 없고, 데이터베이스를 직접 읽을 필요도 없다. 데이터베이스가 인증의 유일한 권한자이기 때문에 발생하는 구조적 문제다.

Defense in Depth: 데이터베이스 외부에서 인증을 검증하라

이 문제의 핵심은 인증 정보의 무결성 검증을 데이터베이스에만 의존한다는 점이다. SQL Injection으로 데이터베이스 레이어가 침해되는 순간, 그 위에 있는 애플리케이션 레이어도 자동으로 함께 침해된다. 각 레이어는 다른 레이어가 실패할 수 있다는 가정 하에 독립적으로 방어해야 한다.

실무적인 대응 방향은 다음과 같다.

  • HMAC 서명 검증: API 키 발급 시 서버가 보유한 마스터 시크릿으로 서명된 값을 키에 포함시킨다. 데이터베이스 조회 이전에, 혹은 조회 결과와 무관하게 서명 자체를 검증하는 단계를 추가한다.
  • 불변 식별자 바인딩: 키에 org_id 등 식별자를 서명 페이로드로 포함시켜, 데이터베이스에서 해당 값이 변경되더라도 서명 검증 단계에서 탐지되도록 설계한다.
  • 데이터베이스 변경 감지: 중요 테이블에 대한 감사 로그(audit log)를 별도 저장소에 기록하여, 비정상적인 UPDATE를 사후 탐지할 수 있는 체계를 마련한다.

이 접근법은 SQL Injection이 발생하더라도, 인증 우회까지 연결되는 공격 체인을 끊어낸다.

정리

  • 데이터베이스를 인증의 유일한 권한자로 설계하면, SQL Injection 하나로 전체 인증 체계가 붕괴될 수 있다.
  • 데이터베이스 외부(애플리케이션 레이어)에서 HMAC 서명 등으로 독립적인 무결성 검증 단계를 두는 것이 핵심 방어 전략이다.
  • 각 레이어는 다른 레이어가 실패할 수 있다는 가정으로 설계해야 한다는 "Defense in Depth" 원칙을 인증 설계에도 적용해야 한다.
Source
Hacker News
원문 보기 →
← 목록으로 돌아가기