사전 자격증명
개념

자격증명

gabury1고친 사람 github-actions[bot]

자격증명은 요청을 보낸 쪽이 누구인지, 무엇을 허락받았는지를 상대에게 증명해 줍니다. 로그인할 때 넣는 비밀번호도, 서버끼리 주고받는 키와 토큰도 자격증명입니다. 받는 쪽은 이것을 확인하고 요청을 들여보낼지 정합니다. 그래서 자격증명이 새면 남이 그 주인 행세를 할 수 있습니다.

쉽고 빠른 이해

자격증명은 「내가 그 사람이 맞다」를 보여 주는 증거입니다. 아이디와 비밀번호 한 벌이 가장 흔한 예입니다.

서버는 요청을 보낸 쪽의 얼굴을 볼 수 없습니다. 요청에 증거가 없으면 누구든 남의 이름을 대고 남의 데이터를 가져갈 수 있습니다.

주고받는 흐름은 이렇습니다.

  1. 서비스가 주인에게 자격증명을 발급합니다
  2. 주인은 요청할 때마다 그것을 함께 보냅니다
  3. 서버는 자기가 아는 값과 맞춰 보고 들여보낼지 정합니다

자격증명에는 관리 부담이 따릅니다. 서버는 자격증명을 누가 내밀었는지 가리지 못합니다. 한 번 새면 훔친 사람도 주인으로 통합니다. 그래서 자격증명은 숨겨 두고, 때맞춰 새것으로 바꾸어야 합니다. 새면 곧바로 무효로 만들어야 합니다.

상세

회사 건물 입구의 보안 요원은 드나드는 직원의 얼굴을 다 외우지 못합니다. 그래서 출입증을 보고 문을 열어 줍니다. 출입증을 대는 사람은 들어가고, 못 대는 사람은 문 앞에서 돌아갑니다.

자격증명(credential)은 요청을 보낸 쪽이 자기 신원이나 받은 권한을 증명하려고 내미는 정보입니다. 로그인 폼에 넣는 아이디와 비밀번호가 그 예입니다. 백엔드 서비스가 결제 서비스를 부를 때 요청 헤더에 싣는 API(Application Programming Interface, 애플리케이션 프로그래밍 인터페이스) 키도 자격증명입니다.

이 편에서는 자격증명을 발급받아 쓰는 쪽을 주인이라고 부릅니다. 주인은 사람일 수도 있고 프로그램일 수도 있습니다. 자격증명을 받아서 확인하는 쪽은 검증자라고 부릅니다.

자격증명이 필요한 까닭은 서버가 상대를 볼 수 없어서입니다. 요청은 네트워크를 건너온 바이트일 뿐입니다. 누구든 남의 아이디를 적어 보낼 수 있습니다. 자격증명이 없으면 서버는 남의 이름을 댄 요청과 주인의 요청을 가르지 못합니다.

이 절은 먼저 자격증명이 어떤 조각으로 이루어지는지 봅니다. 이어서 무엇으로 증명하는지 가르고, 사람과 프로그램이 각각 무엇을 쓰는지 봅니다. 그다음 자격증명 하나가 발급부터 폐기까지 거치는 단계를 그림으로 따라가고, 새었을 때의 피해와 줄이는 방법을 봅니다. 끝으로 자격증명을 넘기지 않고 권한만 나누는 방법, 이 낱말을 더 좁게 쓰는 경우, 자격증명이 필요한 곳을 차례로 봅니다.

이름을 대는 값과 증명하는 값

자격증명은 대개 두 조각이 한 벌입니다. 한 조각은 「나는 누구다」라고 이름을 댑니다. 아이디나 이메일 주소 같은 식별자가 이 일을 합니다.

식별자만으로는 증명이 안 됩니다. 식별자는 남도 알 수 있는 값이기 때문입니다. 주인만 아는 다른 조각이 같이 있어야 합니다. 비밀번호가 이 조각입니다. 이렇게 주인 말고는 모르게 지켜야 하는 값을 시크릿(secret)이라고 부릅니다.

한 조각으로 둘을 다 하는 자격증명도 있습니다. API 키가 그렇습니다. 키 문자열 하나가 누구의 키인지도 알려 줍니다. 그 문자열을 가졌다는 것이 곧 증명이 됩니다.

증명하는 세 갈래

상대가 주장하는 신원이 맞는지 확인하는 일을 인증이라고 합니다. 자격증명은 인증에서 내미는 증거입니다.

무엇을 증거로 삼느냐는 크게 세 갈래로 나뉩니다. 이 갈래를 인증 요소라고 부릅니다.

인증 요소 무엇으로 증명하나 예
아는 것 주인의 머릿속에 있는 값 비밀번호 · 비밀 질문의 답
가진 것 주인 손에 있는 물건 휴대폰에 뜨는 일회용 코드 · 하드웨어 보안 키
주인 자신 몸의 특징 지문 · 얼굴

요소 하나만 쓰면 그 하나가 새는 순간 뚫립니다. 그래서 서로 다른 요소를 둘 이상 섞어 요구하기도 합니다. 이것을 다중 인증이라고 합니다. 비밀번호가 새도 공격자 손에 주인의 휴대폰이 없으면 로그인이 막힙니다.

사람이 쓰는 자격증명

사람은 로그인 화면에서 한 번 자격증명을 냅니다. 서버는 확인이 끝나면 로그인 상태를 가리키는 값을 하나 내줍니다. 세션 식별자나 토큰이 그 값입니다.

그 뒤의 요청은 비밀번호 대신 이 값을 들고 옵니다. 이 값도 발급된 순간부터 자격증명 노릇을 합니다. 이 값을 훔치면 비밀번호를 몰라도 로그인한 사람 행세를 할 수 있습니다.

프로그램이 쓰는 자격증명

프로그램끼리 부를 때는 사람이 끼지 않습니다. 화면에 비밀번호를 칠 사람이 없으니, 미리 받아 둔 값을 설정에 넣어 두고 요청마다 싣습니다. 백엔드 개발자가 가장 자주 다루는 자격증명이 이쪽입니다.

이쪽 자격증명 가운데 인증서와 SSH(Secure Shell, 원격 접속 프로토콜) 키는 짝을 이루는 키 두 개를 씁니다. 하나는 주인만 갖는 개인 키입니다. 다른 하나는 누구에게 줘도 되는 공개 키입니다.

두 키는 서명으로 이어집니다. 서명은 개인 키로만 만들 수 있는 증거값입니다. 주인이 개인 키로 서명을 만들어 보내면, 검증자는 짝이 되는 공개 키로 그 서명이 맞는지 확인합니다. 그래서 검증자는 공개 키만 들고도 상대가 개인 키를 가졌는지 알 수 있습니다.

공개 키만 받아서는 그 키가 누구의 것인지 알 수 없습니다. 그래서 공개 키와 주인의 신원을 한 문서에 적고, 믿을 만한 기관이 그 문서에 서명해 보증합니다. 이 문서가 인증서입니다.

인증서에 서명하는 기관은 인증 기관이라고 부릅니다. 검증자는 이 기관을 믿기 때문에, 기관이 서명한 인증서에 적힌 신원도 믿습니다.

아래 표는 프로그램이 흔히 쓰는 자격증명 넷을 생김새와 확인 방법으로 가릅니다.

종류 생김새 검증자가 확인하는 것
API 키 서비스가 발급한 긴 무작위 문자열 자기가 발급한 키 목록에 있나
액세스 토큰 권한을 내주는 서버가 발급한, 만료 시각이 있는 문자열 발급한 적 있는 값인가 · 아직 안 만료됐나
인증서와 개인 키 인증 기관이 서명한 문서 한 장과, 주인만 가진 짝 키 신뢰하는 인증 기관이 서명했나 · 개인 키로 만든 서명이 맞나
SSH 키 SSH 서버에 들어갈 때 쓰는 공개 키와 개인 키 한 쌍 미리 등록해 둔 공개 키와 짝이 맞나

넷은 확인하는 방식이 두 무리로 갈립니다. API 키와 액세스 토큰은 검증자가 같은 값을 들고 있다가 들어온 값과 맞춰 봅니다. 인증서와 SSH 키는 개인 키가 네트워크로 아예 넘어가지 않습니다. 개인 키는 주인 쪽에 남습니다. 그 키로 만든 서명만 건너갑니다.

자격증명이 거치는 단계

자격증명 하나는 만들어진 뒤 여러 손을 거칩니다. 발급 → 보관 → 요청에 실어 보냄 → 확인 → 폐기 순서입니다. 아래 그림은 그 순서를 발급자 · 주인 · 검증자 셋 사이의 왕복으로 보입니다. 발급자는 자격증명을 만들어 주는 쪽이고, 검증자와 같은 서버일 때가 많습니다.

sequenceDiagram
    participant 발급자
    participant 주인
    participant 검증자
    발급자->>주인: 자격증명을 발급한다
    Note over 주인: 남이 못 보게 보관한다
    주인->>검증자: 요청에 자격증명을 싣는다
    Note over 검증자: 알고 있는 값과 맞춰 본다
    검증자-->>주인: 맞으면 요청을 처리한다
    발급자->>검증자: 폐기한 자격증명을 알린다
    Note over 검증자: 폐기된 값은 거절한다

이 절의 나머지는 그림의 단계를 따라가며 단계마다 자격증명을 어떻게 지키는지 봅니다. 검증자가 쥔 값, 주인이 보관하는 곳, 실어 보내는 길, 폐기하는 법 순서입니다.

먼저 검증자는 확인에 쓸 「알고 있는 값」을 들고 있습니다. 이 값을 어떤 꼴로 들고 있느냐에 따라, 검증자 쪽 저장소가 털렸을 때의 피해가 달라집니다.

비밀번호라면 검증자는 원문을 저장하지 않습니다. 원문 대신 해시 함수를 거친 값을 저장합니다. 여기에 쓰는 해시 함수는 결과에서 입력을 되짚기 어렵게 만든 함수입니다. 로그인할 때 들어온 비밀번호를 같은 함수에 넣어 저장된 값과 비교하면, 원문 없이도 확인이 됩니다.

같은 비밀번호가 늘 같은 결과로 나오면 곤란한 일이 생깁니다. 한 사람의 비밀번호를 알아내면 같은 결과를 가진 사람이 모두 드러납니다. 이를 막으려고 사용자마다 다른 무작위 값을 섞은 뒤 해시합니다. 이 무작위 값을 솔트라고 합니다. 자세한 방법은 비밀번호 해싱이 다룹니다.

주인 쪽에서는 자격증명을 소스 코드에 적지 않습니다. 코드가 저장소에 올라가는 순간 저장소를 볼 수 있는 모든 사람이 그 값을 봅니다. 대신 배포할 때 환경 변수로 넣거나, 자격증명만 따로 맡아 두는 시크릿 관리 도구에서 읽어 옵니다.

요청에 실어 보낼 때는 암호화된 연결 위에서만 보냅니다. 그 연결을 만드는 것이 TLS(Transport Layer Security, 전송 계층 보안)입니다. 암호화하지 않은 연결로 보내면 중간에서 엿보는 쪽이 그 값을 가져갑니다.

마지막 단계는 폐기입니다. 발급자는 더는 통하면 안 되는 자격증명을 검증자에게 알립니다. 검증자는 그 값이 들어오면 거절합니다. 발급자와 검증자가 같은 서버라면 저장해 둔 값을 지우거나 무효로 표시하면 됩니다.

새었을 때의 피해

검증자는 자격증명이 맞는지만 확인합니다. 그것을 내민 쪽이 진짜 주인인지는 알 수 없습니다. 그래서 훔친 자격증명으로 보낸 요청도 주인의 요청과 똑같이 처리됩니다.

자격증명이 흔히 새는 경로는 넷입니다.

새는 경로 흔한 모습
코드 저장소 설정 파일에 넣은 키가 커밋과 함께 올라간다
로그 요청 헤더를 남김없이 찍는 로그에 토큰이 남는다
가짜 로그인 화면 진짜처럼 꾸민 페이지에 사용자가 비밀번호를 친다
다른 서비스의 유출 여러 곳에 같은 비밀번호를 쓰면, 한 곳에서 샌 값으로 다른 곳에 들어간다

가짜 로그인 화면으로 비밀번호를 받아 내는 공격을 피싱이라고 합니다.

다른 서비스에서 샌 비밀번호 목록을 들고 여러 서비스에 차례로 넣어 보는 공격은 크리덴셜 스터핑이라고 부릅니다. 크리덴셜은 자격증명의 영어 이름 credential 을 소리 나는 대로 적은 말입니다.

피해를 줄이는 방법

새는 것을 완전히 막기는 어렵습니다. 새더라도 피해가 작도록 자격증명을 설계해 둡니다. 아래 표는 흔한 방법 넷이 각각 무엇을 줄이는지 보입니다.

방법 줄이는 피해
수명을 짧게 둔다 훔친 값을 쓸 수 있는 시간
할 수 있는 일을 좁힌다 훔친 값으로 할 수 있는 일의 범위
주기적으로 바꾼다 모르는 새 샌 값이 계속 통하는 기간
곧바로 폐기할 수 있게 둔다 유출을 알아챈 뒤에 이어지는 피해

꼭 필요한 권한만 주는 원칙을 최소 권한이라고 부릅니다. 자격증명을 새것으로 갈아 끼우는 일은 키 로테이션이라고 합니다.

수명을 짧게 두는 방법은 흔히 토큰 두 개를 짝지어 씁니다. 요청마다 싣는 액세스 토큰은 수명을 짧게 둡니다. 그것이 만료되면 새 액세스 토큰을 받아 오는 데만 쓰는 리프레시 토큰을 따로 둡니다.

수명이 짧을수록 주인은 새 값을 자주 받아 와야 합니다. 만료를 알아채고 다시 받아 오는 흐름을 코드로 챙겨야 합니다.

자격증명을 넘기지 않고 권한만 나누기

사용자가 다른 서비스에게 자기 계정의 일부를 쓰게 하고 싶을 때가 있습니다. 사진 인화 서비스가 내 사진첩의 사진을 읽어 가는 경우가 그렇습니다. 가장 단순한 길은 그 서비스에 내 비밀번호를 알려 주는 것입니다.

이 길에는 문제가 둘 있습니다. 비밀번호를 받은 쪽은 사진만이 아니라 계정의 모든 일을 할 수 있습니다. 그 서비스 하나만 끊으려 해도 비밀번호를 바꾸는 수밖에 없습니다.

내 권한 일부를 남에게 맡기는 일을 위임이라고 합니다. OAuth 2.0 같은 위임 방식은 비밀번호 대신 따로 자격증명을 발급합니다. 사용자가 허락하면 사진 인화 서비스는 사진 읽기만 허락된, 곧 만료되는 토큰을 받습니다. 이 토큰을 쥐고 요청하는 쪽은 인화 서비스이니, 이 편의 말로는 인화 서비스가 토큰의 주인입니다.

사진첩을 가진 사용자는 따로 자원 소유자라고 부릅니다. 자원 소유자의 비밀번호는 로그인을 받는 서버에만 들어갑니다. 사진 인화 서비스에는 넘어가지 않습니다.

이렇게 받은 토큰은 누구인지보다 무엇을 허락받았는지를 증명합니다. 확인된 상대에게 무엇을 해도 되는지 정하는 일을 인가라고 합니다. 자격증명은 인증에도 쓰이고 인가에도 쓰입니다.

신원 지침에서 쓰는 좁은 뜻

NIST(National Institute of Standards and Technology, 미국 국립표준기술연구소)의 디지털 신원 지침은 이 낱말을 더 좁게 씁니다.

이 좁은 뜻에서는 비밀번호나 보안 키처럼 주인이 들고 있다가 내미는 것을 인증수단(authenticator)이라고 부릅니다. 자격증명은 그 인증수단을 한 사람의 신원에 묶어 두는 기록을 가리킵니다. 「이 보안 키는 김철수의 것이다」라고 적어 둔 기록이 자격증명입니다. 보안 키 자체는 인증수단입니다.

이 뜻을 따르는 글에서 「검증자가 자격증명을 확인한다」는 말은 그 묶음 기록을 본다는 뜻입니다. 기록이 폐기되지 않았는지도 함께 봅니다. 일상 개발 대화에서는 둘을 가르지 않고 비밀번호나 키 자체를 자격증명이라고 부릅니다.

언제 필요한가

요청을 보낸 쪽이 누구인지에 따라 결과가 달라지는 곳이면 자격증명이 필요합니다. 남의 데이터를 읽거나 쓰는 요청, 돈이 드는 외부 서비스 호출이 그렇습니다.

누가 보내도 같은 답을 주는 공개 정보라면 자격증명 없이 엽니다. 공개 문서 페이지나 서비스가 살아 있는지 묻는 상태 확인 주소가 그 예입니다.

관련 항목

자격증명으로 치르는 확인 절차

인증 · 인가 · 인증과 인가 · 다중 인증 · 인증 요소 · 신원 증명 · 싱글 사인온

자격증명의 하위 종류

비밀번호 · API 키 · 액세스 토큰 · 리프레시 토큰 · 세션 · 쿠키 · 인증서 · 개인 키 · SSH 키 · 보안 키 · 일회용 비밀번호 · JWT · 임시 자격증명 · 클라이언트 시크릿

자격증명을 발급하고 확인하는 역할

검증자 · 자원 소유자 · 자격증명 서비스 제공자 · 인증 기관 · 인가 서버 · 자원 서버 · 신뢰 당사자

자격증명을 보관하고 지키는 방법

비밀번호 해싱 · 해시 함수 · 솔트 · 시크릿 관리 · 환경 변수 · 키 로테이션 · 최소 권한 · TLS · 토큰 폐기 · 공개 키

자격증명을 노리는 공격

자격증명 유출 · 피싱 · 크리덴셜 스터핑 · 무차별 대입 공격 · 세션 하이재킹 · 중간자 공격

자격증명 대신 권한을 넘기는 위임 표준

OAuth 2.0 · OpenID Connect · SAML · 클라이언트 자격증명 그랜트 · 인가 그랜트

자격증명을 좁게 정의하는 신원 모델 용어

인증수단 · NIST · 디지털 신원 · 가입자 · 신원 제공자

다른 이름: credential · credentials · 자격 증명 · 크리덴셜