1. 라이브러리
  2. HTTP와 웹
  3. API와 웹 서비스

업데이트됨 1개월 전

모든 API 요청에는 같은 질문이 담겨 있습니다: 당신을 믿을 수 있는가?

인증 없이는 답이 언제나 "예"입니다—모든 사람에게. 누구든 데이터를 읽고, 리소스를 수정하고, 사용자를 사칭할 수 있습니다. API는 자물쇠 없는 문이 되고, 온 동네가 자물쇠가 없다는 걸 알게 됩니다.

인증은 API가 신원을 확인하는 방법입니다. "당신은 누구입니까?"라는 질문에 답함으로써, API는 접근을 허용할지, 그리고 안에 들어온 뒤 무엇을 할 수 있는지 결정합니다.

인증 vs. 권한 부여

두 개념은 함께 작동하지만 서로 다른 문제를 해결합니다.

인증은 신원을 확인합니다. "당신은 누구입니까?"에 답합니다. 유효한 API 키나 액세스 토큰은 당신이 주장하는 사람임을 증명합니다.

권한 부여는 권한을 결정합니다. "무엇을 할 수 있습니까?"에 답합니다. 인증을 통과했다고 해서 모든 사용자를 삭제하거나 다른 사람의 개인 데이터에 접근할 수 있는 건 아닙니다.

모든 API 요청에는 두 가지가 모두 필요합니다: 먼저 신원을 확인하고, 그다음 권한을 확인합니다.

API 키

API 키는 가장 단순한 인증 방식으로, 각 애플리케이션에 발급되는 고유한 문자열입니다.

API 제공자에 등록하면 키(길고 무작위한 문자열)를 받습니다. 모든 요청에 이를 포함합니다:

GET /users
Authorization: ApiKey sk_live_abc123def456

API 키는 서버 간 통신에 적합합니다. 구현이 단순하고, 개발자가 사용하기 쉬우며, 애플리케이션별 사용량 추적이 가능합니다.

중요한 한계: API 키는 사용자가 아닌 애플리케이션을 식별합니다. 내장된 만료 기간이 없고, 세분화된 권한도 없으며, 한 번 노출되면 위험합니다. API 키를 클라이언트 코드에 절대 포함하지 마세요—모바일 앱과 JavaScript는 디컴파일되거나 분석될 수 있어, 코드를 들여다보는 누구에게나 키가 노출될 수 있습니다.

모범 사례: 키를 주기적으로 교체하세요. 개발 환경과 운영 환경에 서로 다른 키를 사용하세요. 반드시 HTTPS를 통해서만 전송하세요.

베어러 토큰

베어러 토큰은 이름 그대로입니다: 가진 사람이 쓸 수 있습니다. 영화 티켓과 같습니다—극장은 누가 샀는지 신경 쓰지 않고, 들고 있는 사람만 확인합니다.

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

흐름은 이렇습니다: 자격 증명으로 한 번 인증하고, 토큰을 받고, 이후 요청에 그 토큰을 포함합니다. 서버는 토큰을 검증하고 요청을 처리합니다.

자격 증명을 매번 보내는 것보다 훨씬 낫습니다. 토큰은 만료될 수 있고, 권한 정보를 담을 수 있으며, 비밀번호를 변경하지 않고도 취소할 수 있습니다. 토큰이 탈취되면 취소하면 됩니다. 비밀번호가 탈취되면 더 큰 문제가 생깁니다.

OAuth 2.0

OAuth는 우아한 문제를 해결합니다: 비밀번호를 넘기지 않고, 서드파티 앱이 내 데이터에 접근하도록 허용하는 방법은?

답은 위임입니다. 특정 작업에 한해, 그리고 마음이 바뀔 때까지만, 제3자에게 나를 대신할 수 있는 권한을 주는 것입니다.

흐름: 서드파티 앱으로 트위터에 게시하고 싶습니다. 앱이 트위터 페이지로 이동시킵니다. 트위터에 직접 로그인합니다(앱은 비밀번호를 볼 수 없습니다). 특정 권한을 승인합니다("트윗 게시 가능"하지만 "계정 삭제 불가"). 트위터가 앱에 토큰을 발급합니다. 앱은 그 토큰으로 사용자 대신 행동합니다.

구성 요소:

  • 액세스 토큰은 API 접근 권한을 부여하며, 일반적으로 단기간(몇 시간 또는 며칠) 유효합니다
  • 리프레시 토큰은 사용자를 번거롭게 하지 않고 새 액세스 토큰을 발급받는 데 씁니다
  • 스코프는 앱이 할 수 있는 것을 정의합니다—"read:posts" vs. "write:posts" vs. "delete:account"

OAuth는 API 키보다 훨씬 복잡합니다. 구현하려면 인증 서버, 토큰 관리, 스코프 검증, 리프레시 토큰 처리가 필요합니다. 대부분의 API는 직접 구축하는 대신 OAuth 제공자(Auth0, Okta, Firebase)를 활용합니다.

JWT (JSON Web Token)

JWT는 자기 완결형 토큰입니다. 서버가 소유자를 조회해야 하는 불투명 토큰과 달리, JWT는 필요한 정보를 자체적으로 담고 있습니다.

JWT는 점으로 구분된 세 부분으로 구성됩니다: 헤더, 페이로드, 서명.

header.payload.signature

페이로드에는 클레임이 포함됩니다—사용자 ID, 권한, 만료 시간:

{
  "sub": "user123",
  "name": "John Doe",
  "role": "admin",
  "exp": 1735689600
}

서명은 토큰이 변조되지 않았음을 보장합니다. 누군가 페이로드를 수정하면 서명이 맞지 않습니다.

장점: 서버에 세션을 저장할 필요가 없습니다. 어떤 서비스든 독립적으로 JWT를 검증할 수 있어 마이크로서비스에 이상적입니다.

단점: 만료 전에는 추가 인프라 없이 JWT를 취소할 수 없습니다. 페이로드는 Base64로 인코딩된 것일 뿐, 암호화가 아닙니다—누구든 읽을 수 있습니다. 모든 데이터를 담기 때문에 단순 토큰보다 크기가 큽니다.

모범 사례: 만료 시간을 짧게 설정하세요(15~60분). 페이로드에 민감한 데이터를 절대 넣지 마세요. 모든 요청에서 서명을 검증하세요.

HTTP 기본 인증

기본 인증은 각 요청마다 사용자 이름과 비밀번호를 Base64로 인코딩해 전송합니다:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Base64는 인코딩이지 암호화가 아닙니다. 요청을 가로채는 사람은 자격 증명을 즉시 디코딩할 수 있습니다. 기본 인증은 꼭 필요한 경우에만, 반드시 HTTPS를 통해 사용하고, 현대적인 API에는 토큰 기반 방식을 권장합니다.

세션 기반 인증

전통적인 웹 애플리케이션은 로그인 후 세션을 생성합니다—서버가 세션 데이터를 저장하고 쿠키를 통해 세션 ID를 전송합니다. 이후 요청에는 쿠키가 포함됩니다.

API에서는 세션 방식이 덜 일반적입니다. 서버가 상태를 유지해야 하고, 도메인 간에 잘 동작하지 않으며, 브라우저가 아닌 클라이언트에는 쿠키가 문제가 될 수 있습니다. 하지만 같은 출처의 웹 프론트엔드가 소비하는 API라면 잘 작동합니다.

시스템 간 인증 (M2M)

사용자 없이 API끼리 통신할 때는 다른 패턴이 적용됩니다:

  • 서비스 계정은 애플리케이션 전용으로 만든 계정입니다
  • 클라이언트 자격 증명 방식의 OAuth 그랜트는 서비스 간 인증을 가능하게 합니다
  • 상호 TLS는 클라이언트와 서버 양쪽에 인증서를 사용합니다
  • API 키는 단순한 서비스 간 인증에 적합합니다

모범 사례

항상 HTTPS를 사용하세요. 자격 증명과 토큰은 전송 중 반드시 암호화되어야 합니다. 평문 HTTP로 인증 정보를 절대 보내지 마세요.

API 키 또는 사용자별 요청 횟수 제한을 구현하세요. 무차별 대입 공격과 남용을 방지합니다.

토큰은 반드시 만료되어야 합니다. 리프레시 토큰 교체와 함께 단기 액세스 토큰을 사용하면 보안과 편의성의 균형을 맞출 수 있습니다.

모든 요청에서 검증하세요. 토큰이 아직 유효하다고 가정하지 마세요—서명, 만료, 권한을 확인하세요.

자격 증명이나 토큰을 절대 로그에 남기지 마세요. API 키나 토큰을 로깅하면 취약점이 됩니다. 반드시 마스킹 처리하세요.

API 키를 주기적으로 교체하세요. 개발자가 서비스 중단 없이 키를 교체할 수 있는 방법을 제공하세요.

환경별로 별도의 자격 증명을 사용하세요. 개발, 스테이징, 운영 환경에는 서로 다른 키가 있어야 합니다.

인증 실패 처리

적절한 상태 코드를 반환하세요:

  • 401 Unauthorized: 자격 증명이 없거나 유효하지 않은 경우
  • 403 Forbidden: 인증은 유효하지만 권한이 부족한 경우

명확한 오류 메시지를 제공하세요:

{
  "error": "authentication_required",
  "message": "No authentication credentials provided"
}

보안 세부 정보를 노출하지 마세요. "비밀번호가 틀렸습니다" vs. "사용자 이름을 찾을 수 없습니다"처럼 구분하지 말고—그냥 "잘못된 자격 증명"이라고만 하세요. 이렇게 하면 공격자가 어떤 사용자 이름이 존재하는지 파악하는 것을 막을 수 있습니다.

반복된 실패 후에는 계정을 잠그세요. 보안 모니터링을 위해 인증 실패를 로그에 기록하세요.

API 인증에 관한 자주 묻는 질문

API 키와 OAuth 토큰의 차이점은 무엇인가요?

API 키는 애플리케이션을 식별합니다—모든 요청에 포함하는 정적 자격 증명입니다. OAuth 토큰은 사용자와 그 사용자의 권한을 식별합니다—일시적이고, 범위가 지정되며, 사용자가 명시적으로 접근을 허용하는 위임 흐름을 통해 발급됩니다. 서버 간 통신에는 API 키를, 서드파티 앱이 사용자 대신 행동해야 할 때는 OAuth를 사용하세요.

JWT와 불투명 토큰 중 무엇을 써야 하나요?

JWT는 자기 완결형이라 여러 서비스가 독립적으로 토큰을 검증해야 하는 마이크로서비스 환경에 잘 맞습니다. 불투명 토큰은 조회가 필요하지만 즉시 취소할 수 있습니다. 즉각적인 취소가 필요하다면(보안에 민감한 서비스) 불투명 토큰을 사용하거나 JWT 취소 목록을 구현하세요. 서비스 전반에 걸쳐 상태 비저장 검증이 필요하다면 만료 시간을 짧게 설정한 JWT를 사용하세요.

모바일 앱에서 API 키를 안전하게 보호할 수 있나요?

완전히 보호하기는 어렵습니다. 모바일 앱은 디컴파일될 수 있고, 내장된 키는 추출될 수 있습니다. 대신 모바일 앱이 사용자를 인증하고 백엔드에서 단기 토큰을 받도록 설계하세요. API 키는 백엔드가 보관하고, 모바일 앱은 임시적인 사용자별 토큰만 받습니다.

액세스 토큰의 만료 시간은 어떻게 설정해야 하나요?

짧을수록 더 안전하지만 편의성이 떨어집니다. 일반적인 기준: 보안에 민감한 서비스는 15분, 일반적인 API는 1시간, 위험도가 낮은 시나리오는 24시간. 사용자가 자주 재인증하지 않아도 되도록 단기 액세스 토큰과 장기 리프레시 토큰을 함께 사용하세요.

이 페이지가 도움이 되었나요?

😔
🤨
😃