인증 없는 인가: 비밀번호 없는 앱 보안

인증과 인가는 서로 다른 문제를 푼다

대부분의 앱은 관문에서 시작합니다. 사용자는 무언가를 하기 전에 먼저 신원을 확립해야 합니다. 이메일을 입력하고, 확인 코드를 받고, 비밀번호를 정하거나, 매직 링크를 따라갑니다. 이 단계가 인증이며, 중앙 권한이 보관하는 기록에 비추어 그 사람이 누구인지 확인하는 과정입니다.

인가는 다른 질문에 답합니다. 이 사람은 무엇을 해도 되는가. 많은 팀이 둘을 하나의 “로그인” 흐름으로 묶지만, 둘은 별개의 동작입니다. 이를 분리하면 유용한 통찰이 드러납니다.

서버는 사용자가 무엇을 해도 되는지를 강제하기 위해 그가 누구인지 알 필요가 없습니다.

JustCall은 이 분리 위에 세워졌습니다. 가입도, 계정 테이블도, 비밀번호도, 서버상의 개인정보도 없습니다. 인가가 시스템 전체를 떠받치고, 전통적 의미의 인증은 존재하지 않습니다. 이를 가능하게 하는 것은 세 가지 구성 요소입니다. 개인 키, 공개 키, 그리고 마스터 키라 부르는 위임된 역할입니다.

공개 키 기반 신원이 계정을 대체하는 방식

JustCall을 처음 열면 브라우저가 로컬에서 비밀을 생성하고 결코 전송하지 않습니다. 그 비밀에서 키 쌍을 유도하고, 공개 쪽이 당신의 사용자 ID가 됩니다.

// The private key is generated on your device. The server never sees it.
privateKey = crypto.randomUUID();

// The PUBLIC half, encoded as text, becomes your user ID.
userId = await derivePublicUserId(privateKey);

식별자는 그것을 가리키는 데이터베이스의 한 행이 아니라 공개 키 그 자체입니다. 이 한 가지 결정이 전통적 계정 시스템이 안고 있는 여러 부담을 없앱니다.

  • 등록 단계 없음. 서버는 ID로 서명된 요청을 처음 본 순간부터 받아들입니다.
  • 이메일도 전화번호도 없음. ID는 개인정보가 아니라 당신 기기의 무작위 비밀에서 유도됩니다.
  • 비밀번호 없음. 저장하고, 해시하고, 유출될 공유 비밀이 없으며, 서버는 오직 공개 키만 보관합니다.
  • 비밀번호 재설정 흐름도 크리덴셜 스터핑도 없음. 공격할 재사용 가능한 자격 증명이 없기 때문입니다.

당신은 서버에 신원을 결코 드러내지 않습니다. 특정 공개 키 뒤의 개인 키를 가지고 있음을 암호학적으로 증명하며, 그 증명이 인가로 충분합니다.

서버가 요청을 인가하는 방법

세션도 로그인 토큰도 없으므로, 각 요청은 자기 자신의 증거를 지닙니다. 클라이언트는 페이로드를 만들고 개인 키로 서명한 뒤 둘 다 보냅니다. 서버에서 인가는 단 한 번의 서명 검증으로 귀결되며, 세션 조회도 자격 증명 저장소 질의도 없습니다.

const isValid = await verifyPayload(
  request.userId,   // the public key = the claimed identity
  request.payload,  // exactly what was signed
  request.signature,
);

if (!isValid) {
  return jsonResponse({ message: "invalid signature" }, 401);
}

유효한 서명은 요청을 한 번의 동작으로 진짜이자 인가된 것으로 만듭니다. 공격자는 개인 키를 갖지 않은 ID의 요청을 위조할 수 없습니다. 일치하는 서명을 만들 수 없기 때문입니다. 개인 키의 소유가 곧 권한입니다.

마스터 키: 비밀을 공유하지 않고 기기를 연결하기

한 기기가 유일한 키를 갖는 모델은 두 번째 기기를 더하는 순간 무너집니다. 전화가 당신 신원의 유일한 키를 갖는다면, 노트북은 시스템에게 낯선 존재입니다.

마스터 키가 이를 해결합니다. 첫 기기가 마스터가 되어, 당신의 ID가 유도되는 원래 비밀을 보관합니다. 추가되는 각 기기는 자기만의 별도 키 쌍을 생성합니다. 새 기기는 당신을 대신해 서명할 수 없고, 마스터 키는 기기 간에 결코 복사되지 않습니다. 연결은 위임으로 작동합니다. 마스터는 새 기기의 공개 키를 당신의 ID에 묶는 짧은 인증서에 서명합니다.

// Only the master can authorize a new device.
const authorization = {
  action: "device-authorization",
  userId: identity.userId,
  devicePublicKey: newDevice.devicePublicKey, // the new device's PUBLIC key
  role: newDevice.role,
  createdAt: Date.now(),
};
const signature = await signPayload(identity.privateKey, authorization);

그 후 새 기기는 자기 키로 자기 요청에 서명하고, 서버는 마스터가 보증한 키에 대해 검증합니다. 마스터는 비밀을 한 번도 드러내지 않고 자격을 발급합니다. 인증 기관이 자신이 개인 키를 갖지 않은 웹사이트를 보증하는 것과 같습니다.

이렇게 운영 단계 권한 시스템의 어휘 전부, 곧 역할, 위임, 폐기, 최소 권한이 오로지 서명으로 표현됩니다. 마스터는 연결된 어떤 기기든 이름을 바꾸거나 폐기할 수 있고, 폐기된 기기는 다음 서명 검증에 실패하며 그 활성 연결이 닫힙니다.

계정 없는 서버가 저장하는 것

데이터베이스에 실제로 무엇이 있는지 보세요. 각 계정이 담는 것은 사용자가 고른 표시 이름, 선택적 아바타, 공개 기기 키 목록입니다. 그 외에는 없습니다. 이메일도, 전화번호도, 비밀번호 해시도, 보안 질문도 없으며, 개인 키도 없습니다. 개인 키는 사용자의 기기를 결코 떠나지 않습니다.

데이터베이스 전체가 유출되는 전형적 침해 시나리오를 생각해 보세요. 공격자가 얻는 것은 설계상 공개이며 대응하는 개인 키 없이는 쓸모없는 공개 키 집합과, 사용자가 고른 몇몇 표시 이름입니다. 누구도 사칭할 수 없습니다. 사칭에는 서버가 한 번도 저장하지 않은 개인 키가 필요하기 때문입니다. 비밀번호 덤프와 대조할 수도 없습니다. 비밀번호가 없기 때문입니다. "당신의 이메일"로 피싱할 수도 없습니다. 한 번도 수집하지 않았기 때문입니다.

시스템은 결코 보관하지 않는 데이터를 유출할 수 없습니다. 개인정보를 지키는 가장 확실한 방법은 수집하지 않는 것이며, ID가 공개 키인 신원 모델은 그것을 말 그대로 실현합니다.

왜 비밀번호 없는 인가가 침해 위험을 낮추는가

공격 면을 직접 비교해 봅시다. 전통적인 이메일·비밀번호 앱은 자격 증명 데이터베이스, 비밀번호 재설정 흐름, 이메일·SMS 코드 전송, 세션 토큰, 그리고 이제 책임져야 하는 규제 대상 개인정보 묶음을 방어해야 합니다. 모두 계정 탈취와 유출 사고의 반복적 원인입니다.

공개 키 모델이 방어할 것은 하나, 사용자가 키를 계속 보관하는 것입니다. 이는 진짜 트레이드오프입니다. 잃어버린 키를 재설정할 중앙 권한이 없기 때문입니다. 그 대가로 앞 목록의 모든 항목이 사라집니다. 서버 침해의 영향은 공격자가 공개 키와 표시 이름을 읽는 범위로 좁아집니다. 애초에 민감하지 않았던 정보입니다.

공개 키 인가를 당신의 앱에 적용하기

이 패턴은 통화 앱을 훨씬 넘어 일반화됩니다.

  • 신원을 키 쌍으로, 사용자 ID를 공개 키로 만드세요. 클라이언트에서 생성하고, 개인 쪽은 결코 전송하지 말고, 서버가 유효한 서명을 처음 보는 순간 계정이 생겨나게 하세요.
  • 세션 확인이 아니라 서명 검증으로 인가하세요. 각 동작은 페이로드와 서명을 지닙니다. 정규화된 바이트에 서명해, 무엇에 서명했는지 클라이언트와 서버가 일치하게 하세요.
  • 마스터 키는 공유가 아니라 위임에 쓰세요. 어떤 주체가 신뢰를 두 번째 기기, 팀원, API 클라이언트로 넓혀야 할 때, 루트 키가 새 키를 위한 범위 한정·폐기 가능 인증서에 서명하게 하세요. 루트 비밀은 결코 움직이지 않습니다.
  • 공개 자료만 저장하세요. 그러면 "유출되면 어떻게 되나"라는 질문의 답이 평범하게 유지됩니다.

출시 전에 주의할 제약이 몇 가지 있습니다. 키 보관이 핵심 문제가 되므로, 운영 시스템은 소셜 리커버리, 선택적 암호화 백업, 하드웨어 키 같은 복구 수단을 더합니다. 서명된 요청은 재생을 막기 위해 타임스탬프나 nonce가 필요합니다. 신원이 없으므로 스팸 방지는 이메일 인증이 아니라 속도 제한이나 초대제로 옮겨갑니다. 어느 것도 모델을 훼손하지 않습니다. 모두 가운데에 비밀번호 데이터베이스를 두지 않을 뿐, 어떤 시스템에나 있는 일상적 과제입니다.

자주 묻는 질문

앱이 어떻게 인증 없이 사용자를 인가할 수 있나요? 개인 키의 소유를 권한으로 취급합니다. 공개 키가 사용자 ID 역할을 하고, 각 동작은 대응하는 개인 키로 서명되며, 서버는 그 서명을 공개 키에 대해 검증합니다. 사용자는 중앙 계정 시스템에 신원을 증명하지 않고도 행동이 허가됨을 증명합니다.

계정 없는 모델이 이메일·비밀번호보다 덜 안전한가요? 대부분의 면에서 더 안전합니다. 유출될 비밀번호 데이터베이스도, 악용될 재설정 흐름도, 잃어버릴 개인정보도 없습니다. 트레이드오프는 키 보관입니다. 사용자가 백업 없이 키를 잃으면, 계정을 복구할 중앙 권한이 없습니다.

인증과 인가의 차이는 무엇인가요? 인증은 당신이 누구인지를 확립합니다. 인가는 당신이 무엇을 해도 되는지를 확립합니다. 대부분의 시스템은 둘을 합치지만, 키 쌍은 전자 없이 후자를 가능하게 합니다.

JustCall 서버가 침해되면 어떻게 되나요? 공격자는 공개 키와 표시 이름을 발견할 것입니다. 공개 키는 공개되도록 만들어졌고, 기기를 결코 떠나지 않는 개인 키 없이는 쓸모없습니다. 훔칠 비밀번호도, 이메일도, 전화번호도 없습니다.

계정 없이 여러 기기를 쓸 수 있나요? 네. 첫 기기가 마스터로 작동하며, 각 새 기기의 공개 키를 당신의 ID에 묶는 인증서에 서명합니다. 마스터 비밀은 결코 복사되지 않으며, 마스터는 언제든 어떤 기기든 폐기할 수 있습니다.

관련 글