paint-brush
하지만, 하지만, 하지만 AUTH는 HaaRrRrRrRrRd입니다~에 의해@dbozhinovski
511 판독값
511 판독값

하지만, 하지만, 하지만 AUTH는 HaaRrRrRrRrRd입니다

~에 의해 Darko Bozhinovski8m2024/08/19
Read on Terminal Reader

너무 오래; 읽다

아니, 그렇지 않아. 지루하고, 번거롭고, 해결된 문제지만... 그렇다고 해서 일괄적으로 어렵다고 부르지 마.
featured image - 하지만, 하지만, 하지만 AUTH는 HaaRrRrRrRrRd입니다
Darko Bozhinovski HackerNoon profile picture


아니, 그렇지 않아. 지루하고, 번거롭고, 해결된 문제지만... 그렇다고 해서 일괄적으로 어렵다고 부르지 마.


저는 "PHP에서 MD5를 사용하여 비밀번호를 해시했습니다"라는 말을 몇 년 동안 했습니다. 물론, 2012년 당시에도 끔찍한 생각이었습니다. 하지만 그 당시에는 auth를 "어렵게" 생각한 적이 없습니다. 그 자체로는 꽤 간단한 일이었습니다. 이메일이나 사용자 이름을 받고, 비밀번호를 받고, 해시(MD5로, "신의 의도대로")하고, 특히 보안을 의식한다면 비밀번호를 [ salt ]합니다. 이 모든 것을 어딘가에, 보통은 데이터베이스에 저장합니다. 짜잔, 가입 완료.


요즘에는 이야기가 바뀌었습니다. "인증은 어렵다"는 말은 HackerNews나 Reddit 클릭 한 번 거리에 있는 늘 존재하는 이야기처럼 느껴집니다. 하지만 정말 그럴까요? 제 생각에, 진실은 인증을 만드는 것이 어렵지 않다는 것입니다. 누구나 배울 수 있고(이 업계에 있는 모든 사람은 기본 사항을 배워야 합니다). 진짜 어려움은 MFA, 사용자 관리, 비밀번호 재설정, 수백 개의 OAuth 공급자 각각, 그리고 다른 공급자의 계정 병합과 같은 추가 기능에 있습니다. 천 번의 상처로 죽는 것과 마찬가지입니다. 인증은 해결된 문제이므로 바퀴를 다시 발명하는 것은 시간을 가장 잘 활용하는 방법이 아닙니다. 하지만 그렇다고 해서 "인증은 어렵다"는 포괄적인 진술이 옳거나 거의 옳다는 것을 의미하지는 않습니다. 실험하고 기본 사항을 이해하고 거기에서 구축해야 합니다. 복잡성은 여러분이 만드는 것의 규모(또는 잠재적 규모)에 따라 커질 뿐입니다.


그럼, 인증은 실제로 얼마나 어려울까요? 자세히 살펴보죠.


옛날에는...

PHP와 md5에 관한 이야기를 멈춘 곳에서 이어서, 로그인 기능을 만드는 단계는 비슷한 단계를 따릅니다. 이메일과 비밀번호를 받고, 저장소에 이메일이 있는지 확인하고, 해당 이메일에 대해 저장된 salt와 비밀번호를 해시하고, 결과 해시를 데이터베이스에 저장된 해시와 비교합니다. 모든 것이 잘 작동하면 setcookie 통해 쿠키를 설정합니다(여전히 PHP 영역에 있지만, 다른 생태계에서 전반적인 논리는 크게 다르지 않았습니다).


로그아웃은 더 간단했습니다. 서버에서 쿠키를 무효화하기만 하면 끝입니다. 서버에서 다음 요청에서 쿠키를 보지 못하면 로그인이 되지 않습니다. 따라서 인증된 경로를 만드는 것도 전반적으로 간단한 시련이었습니다. 권한과 관련하여 상황이 까다로워질 수 있지만, 제가 빌드해야 했던 앱에서는 대부분 관리자와 사용자만 있었습니다. 이는 사용자 레코드와 함께 저장하거나 앱에 대한 역할 수를 확장해야 하는 경우 권한 표에 저장할 수 있는 것이었습니다.


완전 공개—저는 SuperTokens 에서 일합니다. 하지만 이 글은 인증이 일괄적인 진술로서 얼마나 어려운지에 대한 편재하는 이야기에 대한 개인적인 좌절에서 비롯되었습니다. 다시 말해, 저는 "제 물건을 팔려고" 하는 것이 아닙니다. 원하는 대로 사용하세요.


직접 만들어보세요 - "현대적" 스타일

이메일/비밀번호 및 소셜 인증

오늘 우리가 있는 곳으로 가기 위해, 우리는 처음부터 시작할 것입니다... 놀랍죠, 알아요. 우리는 아마도 이러한 구성 요소가 이메일/비밀번호 + 소셜 로그인 PoC를 만드는 데 충분하다는 데 동의할 것입니다.


  1. 가입, 로그인, 로그아웃 등의 경로를 처리하는 서버입니다.
  2. 사용자 레코드를 보관하기 위한 어떤 종류의 저장소(메모리 내 배열도 가능)
  3. 뷰 - 로그인, 가입 및 인증된 "대시보드" 화면.
  4. 소셜 인증에 대한 핸들러


Express와 Passport를 사용하면 바퀴를 새로 발명하지 않으므로 매우 지루하고 반복적인 코드 150줄이 정확히 나옵니다. https://github.com/supertokens/auth-express/blob/master/index.mjs . 다음 섹션은 코드에서 무슨 일이 일어나고 있는지 표면적으로 설명하므로 이미 개념에 익숙하다면 건너뛰어도 됩니다. Express 앱은 어차피 PoC입니다.


잠깐 분석해 보겠습니다.

화면에 물건 렌더링하기

제가 보기에, 이 문제에 접근하는 방법은 두 가지가 있습니다. 렌더링부터 시작해서 인증 경로로 넘어가거나 그 반대입니다. 대부분 우연의 일치로, 저는 FE에 많이 익숙한 사람이 되었습니다(궁금하시다면, 저는 여전히 SQL을 할 수 있습니다). 그래서 "화면에서 렌더링하는 것" 접근 방식으로 시작하겠습니다.


이건 PoC이기 때문에 React-fancy로 갈 생각은 없습니다. ejs를 사용한 평범한 SSR이면 충분합니다: https://github.com/supertokens/auth-express/tree/master/views

경로 추가

몇 가지 passport.js 예시를 기반으로, 이를 더욱 단순화하면, 다음이 필요합니다.

  1. 일부 종속성: npm i passport passport-local express-session . 각각에 대해 간단히 살펴보겠습니다.

    1. Passport.js - Express 및 Node.js를 위한 OG 인증 미들웨어
    2. passport-local - Passport에 대한 인증 전략. 특정 인증 방법에 대한 인증 프로세스를 처리하는 모듈의 인증 전략입니다. 이 경우에는 사용자 이름(이메일)과 비밀번호를 사용하는 로컬 로그인입니다.
    3. express-session - 세션 데이터를 관리하는 미들웨어로, HTTP 요청 간에 사용자 세션을 저장하고 유지할 수 있습니다. 각 클라이언트에 고유한 세션 ID를 할당하여 작동하며, 이는 클라이언트 측의 쿠키에 저장되고 서버에서 세션 데이터를 검색하는 데 사용됩니다.
  2. 사용자를 저장할 장소(위에 링크된 예에서는 메모리 내 배열을 사용): https://github.com/supertokens/auth-express/blob/master/index.mjs#L13

  3. 사용자 조회에 대한 수신 요청을 처리하기 위한 Passport 인스턴스와 LocalStrategy 인스턴스에 대한 구성: https://github.com/supertokens/auth-express/blob/master/index.mjs#L18

  4. Passport( https://github.com/supertokens/auth-express/blob/master/index.mjs#L60 )와 express-session( https://github.com/supertokens/auth-express/blob/master/index.mjs#L69 )을 초기화합니다.


장황하게, 물론이죠. 어렵나요? 저는 그렇게 생각하지 않습니다. 적어도 장난감처럼 구현하는 의미에서는요. 하지만 우리는 얼마 전에 이메일/비밀번호 조합을 사용하는 것을 넘어섰습니다. 우리가 가진 것 위에 소셜 제공자를 추가하는 것이 얼마나 어려운지 살펴보죠.


여기서 제공하는 공급자의 예로, 간단한 이유 때문에 GitHub을 선택했습니다. 처음부터 끝까지 따라가기로 했다면 시작하기 가장 쉬운 공급자 중 하나이기 때문입니다(Google을 보세요).


전체 과정을 따라가기로 결정했다면, GitHub 키를 얻는 방법을 설명하는 다음 링크가 있습니다: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app 그런데, 혹시 걱정되신다면 리포지토리에 있는 키는 유효하지 않습니다 ;)

PoC에 GitHub OAuth2 통합

우선, npm i passport-github2 종속성이 하나 더 필요합니다. passport-github2 는 Passport의 인증 전략으로, 이를 통해 GitHub의 OAuth2 API와 통합할 수 있습니다.


일부 핸들러( https://github.com/supertokens/auth-express/blob/master/index.mjs#L122-L133 )와 구성( https://github.com/supertokens/auth-express/blob/master/index.mjs#L29-L45 )은 나중에, 글쎄요, 그게 다입니다. 복잡할까요? 아마 그렇지 않을 겁니다. 번거롭죠? 물론입니다. 지루할까요? 물론입니다. 특히 계속해서 반복해야 한다면요. 해결된 문제입니다. 바퀴를 다시 발명하는 것은 종종 우리가 확립했듯이 시간을 가장 잘 활용하는 방법이 아닙니다.


큰 아이디어

이제 우리는 Auth가 구축 하기 어렵지 않다는 데 동의할 수 있을 것입니다. 따라서 JWT의 신비로운 언어를 구사하는 흰 수염 마법사만이 이해하고 구현할 수 있는 마법 같은 것은 아닙니다.


아니요, 사실 저는 개발자로서 인증이 어떻게 작동하는지에 대한 기본 사항을 이해해야 한다고 주장하고 싶습니다. 그리고 저는 종종 그렇지 않다고 주장하는 이야기를 봅니다. "저를 믿으세요, 형님. 우리가 당신을 위해 그것을 처리할 수 있어요"라는 내용입니다. 그리고 물론, 저는 대부분의 경우 자체 인증을 롤링하는 것은 시간 낭비라는 데 동의합니다. 하지만 그렇게 구축하기 어렵지 않으며, 확실히 신비로운 것은 아닙니다. 그것이 진정으로 까다로운 부분은 인증과 사용자 경험을 둘러싼 모든 것입니다.


이것을 고려하세요. 위의 예에서 우리는 작동하는 인증이 있습니다. 일종의. 하지만 이것이 할 수 없는 일은 다음과 같습니다(기사 서두에서도 언급됨):

  • 2FA, MFA
  • 비밀번호 재설정
  • 수백 개의 OAuth 제공자와 그 특성
  • 사용자 관리
  • 다양한 공급업체의 계정이 병합되었습니다.
  • 가능한 모든 예외 상황과 잠재적 보안 취약점을 처리합니다.
  • ...그리고 계속할 수 있어요


우리는 아마도 이 중 각각을 구현할 수 있을 것입니다. 그리고 그 자체로, 각 부분은 간단하다고 여겨질 수 있습니다. 하지만 합산하면 됩니다. 그러므로 반드시 구현이 중요한 것은 아닙니다. 구현을 유지하고, 책임을 지고, 표준을 최신 상태로 유지하고, 보안 침해를 방지하는 등의 작업이 필요합니다. 더불어 손을 들어보세요. RFC를 읽는 것을 좋아하는 분이 몇 명이나 되시나요? 우리가 모임에 참석했다면 손을 드는 사람이 많지 않을 것 같습니다.


제가 말하고자 하는 것은 인증이 전체적으로 보면 쉽지 않다는 것입니다. 물론, 위에서 한 것처럼 PoC를 위해 무언가를 쉽게 조립할 수는 있습니다. 하지만 마법 같은 것은 아니고, 이해하기 불가능한 것도 아니며, 그렇다고 말하지 마십시오. 제 생각에는 그런 사고방식(과 마케팅)은 업계 전체에 해롭습니다.


그렇다면 자연스럽게 이어지는 질문은 언제 자체 생산을 시작해야 할까요?

장난감 프로젝트, 인디 및 교육 활동

...물론이죠. 저는 그것을 장려합니다. 당신은 실천하면서 많은 것을 배우게 되니, 왜 안 하시겠습니까? 인디/토이 프로젝트나 블로그가 상당한 사용자 기반이나 팔로워를 확보하게 되면, 그것을 서비스, 셀프 호스팅 솔루션 또는 다른 것으로 전환하세요. 결국, 그 시점에 당신은 제품을 가지고 있고, 당신의 시간은 의심할 여지 없이 신뢰성을 유지하는 대신 그 제품을 만드는 데 더 잘 쓰일 것입니다.

스타트업

일반적으로 제품을 빌드하는 경우 자체 인증을 하지 마세요. 매우 지루하고 번거로운 바퀴를 새로 만드는 것입니다. 선택할 수 있는 옵션이 많습니다. 게다가 무언가를 빌드하고 있지 않나요? 제품이 인증이 아니라면 왜 이런 대화를 나누는 건가요?

스케일업 이상(정의 방법은 당사가 선택)

하지 마세요. 스타트업과 같은 이유지만, 확실히 여기서 더 많이 적용됩니다.


아마 제가 말하고자 하는 바를 알 수 있을 겁니다. "Auth is hard"는 포괄적인 진술로 사용될 때 마케팅 피치라고 말하고 싶습니다. Auth를 이해할 수 있고, 구축할 수 있지만 지루하고, 유지하기가 재미없고, 해결해야 할 문제입니다. 따라서 상품으로 간주될 수 있습니다. 즉, 선반에서 원하는 맛으로 골라낼 수 있는 상품입니다(아래 몇 가지 옵션 참조).

셀프 호스팅 및 FOSS 환경

스택을 소유하는 것을 좋아하는 사람(당신도 그렇듯이)이라면 선택할 수 있는 옵션도 많습니다.

인증 라이브러리

  • Passport.js는 위에서 자세히 다루었습니다.
  • Lucia - 개발자 경험과 사용 편의성에 초점을 맞춘 현대적 웹 애플리케이션을 위한 간단하고 유연한 인증 라이브러리입니다.
  • Auth.js - 다양한 프레임워크와 애플리케이션에 쉽게 통합되도록 설계된 Node.js용 가볍고 사용자 정의 가능한 인증 라이브러리. Next용 라이브러리로 시작됨.

인증 서버

  • Keycloak - 단일 로그인(SSO), ID 브로커링, 사용자 연합과 같은 기능을 제공하는 오픈소스 ID 및 액세스 관리 서버입니다.
  • SuperTokens (위의 면책 조항 참조) - 보안과 단순성에 초점을 맞춘 세션 관리, 소셜 로그인, 이메일/비밀번호 인증과 같은 사전 구축된 기능을 제공하는 오픈소스 인증 솔루션입니다.
  • FusionAuth - 개발자를 대상으로 한 유연한 인증 플랫폼으로 사용자 관리, 다중 인증(MFA), 단일 로그인(SSO)과 같은 기능을 제공합니다.
  • Authelia - 역방향 프록시를 사용하여 애플리케이션을 보호하도록 설계된 다중 인증(MFA) 및 SSO를 제공하는 오픈소스 인증 서버입니다.

저장소 + 인증

  • Supabase - 데이터베이스, 인증, 실시간 기능을 제공하는 오픈소스 백엔드 즉 서비스(BaaS) 플랫폼으로, Firebase 대안으로 설계되었습니다.
  • Pocketbase - 데이터베이스, 인증, 파일 저장을 결합한 오픈소스 백엔드 솔루션으로, 현대적 웹과 모바일 애플리케이션의 개발을 단순화하는 것을 목표로 합니다.


따라서 인증을 위해 타사 소프트웨어를 사용하고 싶지 않더라도 필요와 선호도에 따라 기성품인 오픈소스 소프트웨어를 골라 사용하면 됩니다.

요점: 인증은 개발의 "관료주의"입니다.

제가 "큰" 요점은 바퀴를 다시 발명하지 않는 것입니다. 특히, Auth가 그렇듯이 이미 해결된 문제라면 더욱 그렇습니다. 해당 바퀴에 대해 교육을 받고, 실험하고, 장난감 바퀴를 만들고, 이해하세요. 하지만 제발, 이해하고 만들기가 엄청나게 어려운 것으로 판매하지 마세요. 교육하고, 게이트키핑하지 마세요.