본문으로 건너뛰기

보안

환대처럼 느껴지는 보안.

ID 공급자의 수준은 테넌트 사이의 벽이 얼마나 튼튼한지, 시크릿을 얼마나 신중하게 다루는지에 달려 있습니다. Usher Identity가 어떻게 만들어졌는지 소개합니다. 소프트웨어가 하는 일을 설명할 뿐, 인증을 받았다고 주장하지는 않습니다.

아키텍처

분리된 도메인, 분리된 네트워크.

Usher Identity 자체 페이지와 각 고객의 발급자는 서로 다른 등록 가능 도메인에 있습니다. 데이터베이스는 인터넷에 닿을 수 없는 네트워크에 있으며, 밖으로 나가는 유일한 길은 목적지를 확인하는 프록시입니다.

  • Caddy가 모든 호스트의 TLS를 종료하고, Usher Identity 자체 서비스만 설정할 수 있는 헤더를 제거합니다.
  • 인증 계층은 모든 환경의 요청에 응답하며, 호스트로 환경을 구분합니다. 한 호스트를 위해 캐시한 내용을 다른 호스트에 제공하는 일은 없습니다.
  • 각 서비스는 자체 사용자로 Valkey에 접속하며, 자기 키에만 접근할 수 있습니다. 기본 사용자는 없습니다.
  • 토큰과 코드가 담긴 SQL 문은 그 값과 함께 데이터베이스 로그에 기록되지 않습니다.

인터넷

사용자, 내 앱, 내 서버

에지

Caddy: TLS, HSTS, 내부 헤더 제거

usheridentity.com

사이트와 Console

usheridentity.com, console.usheridentity.com

API

api.usheridentity.com

*.usherid.com

인증 계층

모든 환경의 발급자와 Lobby

데이터 네트워크 · 외부 경로 없음

Postgres

환경마다 하나의 스키마

Valkey

각 서비스는 자기 키에만 접근

밖으로 나가는 유일한 길

이그레스 프록시

고객이 제공한 모든 URL용

디스커버리, JWKS, 로그아웃

공개 주소만 허용

Usher Identity의 계층 구조. 테넌트 도메인은 플랫폼과 다른 등록 가능 도메인이므로, 테넌트의 페이지는 절대 Console과 동일 사이트(same-site)가 되지 않습니다.

격리

중요한 것은 하나도 공유하지 않습니다.

각 프로젝트 환경에는 자체 Postgres 스키마, 자체 서명 키, 그리고 자체 데이터 키로 봉인된 자체 시크릿이 주어집니다. 발급자는 테넌트 도메인의 호스트이고 쿠키는 호스트 전용이므로, 브라우저가 한 환경의 쿠키를 다른 환경으로 보내는 일은 없습니다.

usheridentity.com

사이트, Usher Identity Console, Usher Identity 계정

*.usherid.com

환경마다 하나의 발급자, 별도의 도메인에

환경

사용자, 세션, 토큰은 이 환경을 위해 만든 스키마에 저장됩니다. 쿼리는 항상 이 스키마를 대상으로 실행되며, 테넌트 열이 있는 공유 테이블은 절대 사용하지 않습니다.

Acme 프로덕션 환경의 봉인된 Google 클라이언트 시크릿을 Northwind 프로덕션 환경으로 복사해 보세요.

저장 데이터 암호화

제자리에 묶인 봉투 암호화.

Usher Identity에 맡긴 시크릿은 한 환경에 속한 데이터 키 아래 AES-256-GCM으로 봉인됩니다. 데이터 키는 다시 데이터베이스 밖에 보관되는, 버전이 관리되는 마스터 키로 래핑됩니다.

환경별 데이터 키
한 환경의 데이터 키가 노출되어도 다른 환경에 대해서는 아무것도 드러나지 않습니다.
AAD 바인딩
모든 암호문에 환경과 용도가 묶여 있으므로, 값을 다른 행이나 테넌트로 옮길 수 없습니다.
버전이 있는 키
봉인된 값마다 만들 때 사용한 키 버전을 기록하므로, 키를 교체하고 기존 값을 다시 래핑할 수 있습니다.
인증 암호화
GCM의 태그 덕분에, 변조된 값은 다른 내용으로 복호화되지 않고 아예 열리지 않습니다.
  1. 마스터 키

    데이터베이스 밖에 보관, 버전 관리

  2. 데이터 키, 환경마다 하나

    마스터 키로 래핑

  3. 시크릿

    데이터 키 아래 AES-256-GCM으로 봉인

u1.<key version>.<iv>.<ciphertext + tag>

aad = u1 | version | environment | purpose

봉인된 값은 인증 데이터에 자신의 환경과 용도를 기록합니다. 다른 곳으로 복사하면 열리지 않습니다.

보안 관행

세부 사항까지 신중하게.

  • 암호를 사용한다면

    OWASP 권장 비용(19MiB, 2회 반복)의 Argon2id로 해시하며, 동시에 실행되는 해시 수를 제한해 로그인 요청이 몰려도 서비스가 멈추지 않게 합니다. 새 암호는 Have I Been Pwned의 범위 API로 알려진 유출 사례와 대조하며, 이 API는 암호 해시의 짧은 앞부분만 받습니다. 최소 길이는 기본 12자입니다.

  • 재전송에 쓰일 수 있는 것은 저장하지 않습니다

    클라이언트 시크릿, 토큰, 매직 링크 토큰, 이메일 코드는 해시로 저장됩니다. 백업 코드는 암호화됩니다. 인가 코드는 5분 동안 유효하며, 이메일 코드는 세 번까지 시도할 수 있습니다.

  • 모든 문에 요청 제한

    로그인, 가입, 이메일 코드, 매직 링크, 암호 재설정, 2차 인증 확인에는 각각 별도의 제한이 있습니다. 예를 들어 암호 로그인은 1분에 10회, 이메일 코드는 10분에 5회까지입니다.

  • 엄격한 Content-Security-Policy

    모든 Lobby 페이지는 새 논스(nonce)와 그에 맞춰 만든 정책을 받습니다. 이 출처의 스크립트 중 논스가 있는 것만 실행되고, 양식은 같은 출처로만 전송되며, 다른 사이트는 이 페이지를 프레임에 넣을 수 없습니다.

  • 믿을 수 있는 감사 로그

    워크스페이스, 프로젝트, 환경의 변경 사항은 추가만 가능한 로그에 기록되며, 각 항목은 바로 앞 항목과 해시 체인으로 연결됩니다. 따라서 수정되거나 빠진 항목이 있으면 바로 드러납니다.

  • 고객 URL을 위한 이그레스 프록시

    고객이 제공한 주소로 Usher Identity가 보내는 모든 요청(OIDC 디스커버리, JWKS, 백채널 로그아웃)은 하나의 프록시를 거쳐 나갑니다. 프록시는 이름을 한 번만 조회하고, 사설, 루프백, 링크 로컬, 클라우드 메타데이터 주소를 거부하며, 확인한 바로 그 주소로 연결합니다. 따라서 DNS 리바인딩으로 고객 URL을 내부 주소로 바꿀 수 없습니다.

  • 두 번 다시 배정되지 않는 핸들

    프로덕션 환경의 핸들은 발급자 주소의 첫 번째 레이블입니다. Console은 초대를 받아야 쓸 수 있고, 피싱으로 신고된 Lobby는 정지되며, 한 번 사용된 핸들은 다시는 배정되지 않습니다. 오래된 앱이 여전히 그 핸들의 토큰을 신뢰하고 있을 수 있기 때문입니다.

  • 원할 때 끝나는 세션

    Usher Identity는 캐시된 사본을 믿지 않고 요청마다 자체 세션을 확인하므로, 세션을 끝내면 즉시 종료됩니다. 액세스 토큰은 유효 기간이 짧으며(기본 10분), API에서 인트로스펙션할 수 있습니다.

책임 있는 공개

문제를 발견하셨나요? 먼저 알려 주세요.

Usher Identity에서 보안 문제를 발견했다고 생각되면 꼭 알려 주세요. 문제를 해결할 수 있도록 함께 협력하겠습니다.

security@usheridentity.com
  • 발견한 내용, 위치, 재현 방법.
  • 알고 계신 범위에서, 누군가 이를 이용해 할 수 있는 일.
  • 연락받을 방법과 공로 표기를 원하시는지 여부.

본인이 소유한 환경에서만 테스트하고, 다른 사람의 데이터에 접근하지 말며, 공개하기 전에 문제를 해결할 수 있도록 합리적인 시간을 주세요. Usher Identity 로그인 페이지를 사칭하는 페이지를 신고하려면 악용 신고를 참고하세요.