본문 바로가기

인증과 권한 관리 기초

신원 확인과 접근 허용을 구분하고 세션·토큰 인증, 역할·속성 기반 권한, 비밀번호 해시 원칙을 익힙니다.

앞 글 웹 보안 기초 (HTTPS, XSS, CSRF)에서는 요청이 지나가는 구간마다 방어를 겹쳐 두는 방법을 살펴봤습니다. 그 가운데 서버에서 꼭 해야 하는 일이 인증(authentication)과 인가(authorization, 권한 부여라고도 합니다)입니다. 대부분의 웹 애플리케이션은 로그인한 사용자에게 맞춘 화면을 보여 주고, 역할에 따라 쓸 수 있는 기능을 제한해야 하므로, 인증과 권한 관리는 웹 보안의 핵심입니다.

이 글에서는 인증과 인가를 구별하고, 세션 기반 인증과 토큰 기반 인증이 어떻게 동작하는지, 역할과 속성으로 권한을 관리하는 기본 원칙은 무엇인지 정리합니다.


인증과 권한 부여

두 용어는 자주 섞어 쓰이지만 뜻이 분명히 다릅니다. 인증은 누구인지 확인하는 과정으로, 사용자가 주장하는 신원이 실제와 맞는지 검증합니다. 아이디와 비밀번호로 로그인하거나, 지문을 인식하거나, 일회용 비밀번호(OTP)를 입력하는 것이 인증입니다.

인가는 무엇을 할 수 있는지 정하는 과정으로, 인증된 사용자가 특정 데이터나 기능에 접근해도 되는지를 판단해 허락하거나 거부합니다. 로그인한 사용자가 자기 프로필을 고칠 수 있는지, 관리자만 게시물을 지울 수 있는지, 유료 구독자만 프리미엄 콘텐츠를 볼 수 있는지를 판단하는 것이 인가입니다. 줄여서 인증은 신원 확인이고, 인가는 허락된 작업의 범위를 정하는 일입니다.

이 글의 보호된 API는 인증으로 신원을 확인한 뒤 권한을 검사합니다. 다만 공개된 글처럼 로그인하지 않은 사용자에게도 허락하는 접근이 있으므로, 모든 권한 정책에 로그인이 필요한 것은 아닙니다.

인증·인가 요청 게이트 — 상태 추적

본문 보호 API에서 자격 증명 검증 실패 401, 역할 거부 403, 허용 handler의 도달 여부가 달라진다. 로그인과 작업 인가를 별도 현재 상태로 보여 줄 수 있다.

로그인 성공 뒤에도 작업 권한을 확인합니다

AUTHENTICATION & AUTHORIZATION

로그인 성공 뒤에도 작업 권한을 확인합니다

인증은 신원·자격 증명을 확인하고, 인가는 요청한 자원과 행동의 허용 여부를 결정합니다. 보호 API의 두 검사를 분리합니다.

인증 뒤에도 요청한 역할과 작업을 검사한다원Express예제6노드5분기다. 없는토큰/검증오류는401challenge. 유효한자격증명만역할인가에들어가고거부403/허용handler다. admin-dashboard는admin만,게시물생성은admin또는user가허용된다. 원간략코드의Bearer스킴파싱·검증옵션·대상소유권검사는생략이며그림의유효노드가이를새구현한것은아니다. mobile동일하다.보호 API 요청원 middleware 예제자격 증명유효한가?401인증 challenge이 역할의작업을 허용?403인가 거부핸들러 실행기타 검증은 별도실패유효거부허용
인증 뒤에도 요청한 역할과 작업을 검사한다원Express예제6노드5분기다. 없는토큰/검증오류는401challenge. 유효한자격증명만역할인가에들어가고거부403/허용handler다. admin-dashboard는admin만,게시물생성은admin또는user가허용된다. 원간략코드의Bearer스킴파싱·검증옵션·대상소유권검사는생략이며그림의유효노드가이를새구현한것은아니다. mobile동일하다.보호 API 요청원 예제 범위자격 증명유효한가?401인증 challenge이 역할의작업을 허용?403인가 거부핸들러 실행기타 검증성공 여부는 별도실패유효거부허용
인증과 인가의 요청 분기보호 API 요청의 인증 실패는 401, 인증 후 인가 거부는 403, 모두 통과한 요청은 업무 처리로 이어집니다.보호 API 요청인증이 필요한 자원 예인증 · 자격 증명 유효?세션 · 토큰 검증401 · 유효한 인증 필요실패 응답 · 작업 중단없음·실패유효인가 · 이 작업 허용?역할 · 대상 · 소유 관계403 · 작업 거부유효한 인증 · 권한 부족거부허용업무 처리다른 검증·오류 처리도 필요
  1. 인증 · 자격 증명 확인

    세션·토큰이 없거나 유효하지 않으면 401로 중단합니다. 유효하면 인가로 진행합니다.

  2. 인가 · 대상과 작업 확인

    역할뿐 아니라 필요한 대상·소유 관계를 확인합니다. 권한이 없으면 403, 허용하면 업무 처리로 진행합니다.

  3. 업무 처리

    통과 뒤에도 입력·업무 검증에 실패할 수 있으므로 성공 응답이 항상 보장되지는 않습니다.

교재의 Express 미들웨어

authenticateToken → authorizeRoles → handler 순서입니다. admin-dashboard는 admin 역할, 게시물 생성은 admin 또는 user 역할을 허용합니다.

공개 자원과 응답 정책

공개 자원은 로그인 없이도 정책상 허용할 수 있습니다. 민감한 대상의 존재를 숨기려고 404를 선택하는 정책은 별도로 설계합니다.

401은 유효한 인증 자격 증명이 필요하다는 뜻이며 적절한 WWW-Authenticate 헤더를 포함합니다. 403은 서버가 요청 처리를 거부한다는 뜻으로, 모든 경우를 단순히 “신원을 알고 있음”으로 정의하지 않습니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
  • 세 장면은 서로 독립적인 보호 API 요청 A·B·C의 비교입니다. 401 응답 뒤 같은 요청이 403이나 허용으로 진행하지 않습니다. 이 예제의 403은 인증을 통과했지만 요구 역할이 부족한 경우입니다.
관계도의 보충 설명
원도표의 전체 관계·조건·설명
구분내용
전체 관계·조건 설명원 Express 예제의 노드 6개·분기 5개다. 없는 토큰/검증 오류는 401 challenge로 응답한다. 유효한 자격 증명만 역할 인가에 들어가고 거부 403/허용 handler로 갈린다. admin-dashboard는 admin만, 게시물 생성은 admin 또는 user가 허용된다. 원 간략 코드의 Bearer 스킴 파싱·검증 옵션·대상 소유권 검사는 생략이며 그림의 유효 노드가 이를 새로 구현한 것은 아니다. mobile도 동일하다.
원도표 조건·주석인증 · 자격 증명 확인: 세션·토큰이 없거나 유효하지 않으면 401로 중단합니다. 유효하면 인가로 진행합니다.
원도표 조건·주석인가 · 대상과 작업 확인: 역할뿐 아니라 필요한 대상·소유 관계를 확인합니다. 권한이 없으면 403, 허용하면 업무 처리로 진행합니다.
원도표 조건·주석업무 처리: 통과 뒤에도 입력·업무 검증에 실패할 수 있으므로 성공 응답이 항상 보장되지는 않습니다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
요청 A · 인증 없음HTTP: 401 / handler: 실행 안 함보호 경로에서 유효한 신원을 얻지 못했다신원을 확인하지 못해 요청을 중단한다
요청 B · 역할 부족HTTP: 403 / handler: 실행 안 함신원은 있으나 요구 권한이 없다요청 B는 인증을 통과해도 요구 역할이 없어 인가 단계에서 중단한다
요청 C · 허용HTTP: 업무 handler 결과 / handler: 실행신원과 역할 조건을 모두 통과한다권한 확인 뒤에만 보호 동작을 수행한다

인증·인가 요청 게이트 — 상태 추적

본문 보호 API에서 자격 증명 검증 실패 401, 역할 거부 403, 허용 handler의 도달 여부가 달라진다. 로그인과 작업 인가를 별도 현재 상태로 보여 줄 수 있다.

로그인 성공 뒤에도 작업 권한을 확인합니다

AUTHENTICATION & AUTHORIZATION

로그인 성공 뒤에도 작업 권한을 확인합니다

인증은 신원·자격 증명을 확인하고, 인가는 요청한 자원과 행동의 허용 여부를 결정합니다. 보호 API의 두 검사를 분리합니다.

인증 뒤에도 요청한 역할과 작업을 검사한다원Express예제6노드5분기다. 없는토큰/검증오류는401challenge. 유효한자격증명만역할인가에들어가고거부403/허용handler다. admin-dashboard는admin만,게시물생성은admin또는user가허용된다. 원간략코드의Bearer스킴파싱·검증옵션·대상소유권검사는생략이며그림의유효노드가이를새구현한것은아니다. mobile동일하다.보호 API 요청원 middleware 예제자격 증명유효한가?401인증 challenge이 역할의작업을 허용?403인가 거부핸들러 실행기타 검증은 별도실패유효거부허용
인증 뒤에도 요청한 역할과 작업을 검사한다원Express예제6노드5분기다. 없는토큰/검증오류는401challenge. 유효한자격증명만역할인가에들어가고거부403/허용handler다. admin-dashboard는admin만,게시물생성은admin또는user가허용된다. 원간략코드의Bearer스킴파싱·검증옵션·대상소유권검사는생략이며그림의유효노드가이를새구현한것은아니다. mobile동일하다.보호 API 요청원 예제 범위자격 증명유효한가?401인증 challenge이 역할의작업을 허용?403인가 거부핸들러 실행기타 검증성공 여부는 별도실패유효거부허용
인증과 인가의 요청 분기보호 API 요청의 인증 실패는 401, 인증 후 인가 거부는 403, 모두 통과한 요청은 업무 처리로 이어집니다.보호 API 요청인증이 필요한 자원 예인증 · 자격 증명 유효?세션 · 토큰 검증401 · 유효한 인증 필요실패 응답 · 작업 중단없음·실패유효인가 · 이 작업 허용?역할 · 대상 · 소유 관계403 · 작업 거부유효한 인증 · 권한 부족거부허용업무 처리다른 검증·오류 처리도 필요
  1. 인증 · 자격 증명 확인

    세션·토큰이 없거나 유효하지 않으면 401로 중단합니다. 유효하면 인가로 진행합니다.

  2. 인가 · 대상과 작업 확인

    역할뿐 아니라 필요한 대상·소유 관계를 확인합니다. 권한이 없으면 403, 허용하면 업무 처리로 진행합니다.

  3. 업무 처리

    통과 뒤에도 입력·업무 검증에 실패할 수 있으므로 성공 응답이 항상 보장되지는 않습니다.

교재의 Express 미들웨어

authenticateToken → authorizeRoles → handler 순서입니다. admin-dashboard는 admin 역할, 게시물 생성은 admin 또는 user 역할을 허용합니다.

공개 자원과 응답 정책

공개 자원은 로그인 없이도 정책상 허용할 수 있습니다. 민감한 대상의 존재를 숨기려고 404를 선택하는 정책은 별도로 설계합니다.

401은 유효한 인증 자격 증명이 필요하다는 뜻이며 적절한 WWW-Authenticate 헤더를 포함합니다. 403은 서버가 요청 처리를 거부한다는 뜻으로, 모든 경우를 단순히 “신원을 알고 있음”으로 정의하지 않습니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
  • 세 장면은 서로 독립적인 보호 API 요청 A·B·C의 비교입니다. 401 응답 뒤 같은 요청이 403이나 허용으로 진행하지 않습니다. 이 예제의 403은 인증을 통과했지만 요구 역할이 부족한 경우입니다.

관계도의 보충 설명

원도표의 전체 관계·조건·설명
구분내용
전체 관계·조건 설명원 Express 예제의 노드 6개·분기 5개다. 없는 토큰/검증 오류는 401 challenge로 응답한다. 유효한 자격 증명만 역할 인가에 들어가고 거부 403/허용 handler로 갈린다. admin-dashboard는 admin만, 게시물 생성은 admin 또는 user가 허용된다. 원 간략 코드의 Bearer 스킴 파싱·검증 옵션·대상 소유권 검사는 생략이며 그림의 유효 노드가 이를 새로 구현한 것은 아니다. mobile도 동일하다.
원도표 조건·주석인증 · 자격 증명 확인: 세션·토큰이 없거나 유효하지 않으면 401로 중단합니다. 유효하면 인가로 진행합니다.
원도표 조건·주석인가 · 대상과 작업 확인: 역할뿐 아니라 필요한 대상·소유 관계를 확인합니다. 권한이 없으면 403, 허용하면 업무 처리로 진행합니다.
원도표 조건·주석업무 처리: 통과 뒤에도 입력·업무 검증에 실패할 수 있으므로 성공 응답이 항상 보장되지는 않습니다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
요청 A · 인증 없음HTTP: 401 / handler: 실행 안 함보호 경로에서 유효한 신원을 얻지 못했다신원을 확인하지 못해 요청을 중단한다
요청 B · 역할 부족HTTP: 403 / handler: 실행 안 함신원은 있으나 요구 권한이 없다요청 B는 인증을 통과해도 요구 역할이 없어 인가 단계에서 중단한다
요청 C · 허용HTTP: 업무 handler 결과 / handler: 실행신원과 역할 조건을 모두 통과한다권한 확인 뒤에만 보호 동작을 수행한다

위 그림은 보호된 API로 들어온 요청이 두 단계의 검사를 거치는 모습입니다. 먼저 인증 단계에서 세션이나 토큰 같은 자격 증명이 유효한지 확인합니다. 자격 증명이 없거나 유효하지 않으면 401로 응답하고 작업을 멈춥니다. 유효하면 인가 단계로 넘어가, 이 사용자가 요청한 작업을 해도 되는지 역할뿐 아니라 대상과 소유 관계까지 확인합니다. 권한이 없으면 403으로 거부하고, 허락되면 핸들러가 업무를 처리합니다.

그림은 이 글의 Express 미들웨어 예제를 그대로 옮긴 것으로, authenticateToken, authorizeRoles, 핸들러의 순서로 실행됩니다. 관리자 화면(admin-dashboard)은 admin 역할만, 게시물 생성은 admin이나 user 역할을 허락합니다. 두 검사를 통과해도 입력이나 업무 규칙의 검증에서 실패할 수 있으므로, 성공 응답이 항상 보장되는 것은 아닙니다. 예제 코드는 Bearer 형식의 확인, 토큰 검증의 세부 옵션, 대상의 소유자 확인을 생략했습니다.

그림 아래의 설명처럼 401은 유효한 인증 자격 증명이 필요하다는 뜻이며, 어떤 방식으로 인증해야 하는지 알려 주는 WWW-Authenticate 헤더를 함께 보냅니다. 403은 서버가 이 요청을 처리하지 않겠다는 뜻입니다. 공개 자원은 로그인 없이 허락할 수 있고, 민감한 대상이 있는지조차 숨기려고 403 대신 404를 돌려주는 정책은 따로 정합니다.


사용자 인증 방식

웹 애플리케이션이 사용자를 인증하는 대표적인 방식은 세션 기반 인증과 토큰 기반 인증입니다. 두 방식 모두 로그인할 때 한 번 신원을 확인하고, 그 뒤의 요청마다 이미 확인된 사용자라는 표시를 함께 보냅니다. 차이는 그 상태를 서버가 기록해 두느냐, 서명한 토큰에 담아 클라이언트가 들고 다니느냐에 있습니다. 아래에서 두 방식을 차례로 보고 비교합니다.

세션 기반 인증

세션 기반 인증(session-based authentication)은 전통적인 웹 애플리케이션에서 널리 쓰여 온 방식입니다. 사용자가 아이디와 비밀번호로 로그인하면, 서버는 신원을 확인한 뒤 예측하기 어려운 세션 ID를 만들어 서버의 메모리나 데이터베이스에 사용자 정보와 함께 저장하고, 그 세션 ID를 담은 쿠키를 응답으로 보냅니다. 브라우저는 이 쿠키를 저장해 두었다가, 도메인과 경로, Secure와 SameSite 속성, 요청의 자격 증명(credentials) 조건에 맞는 요청마다 함께 보냅니다. 서버는 요청에 담긴 세션 ID를 저장된 세션과 비교해 일치하면 로그인한 사용자로 보고 요청을 처리하며, 로그아웃하면 서버의 세션 정보를 지웁니다.

세션 방식은 사용자 정보를 서버에 두고, 세션의 만료나 강제 로그아웃을 서버가 직접 제어할 수 있습니다. 다만 유효한 세션 ID는 로그인 상태에 연결된 비밀이라서, 탈취되면 그 세션을 악용할 수 있으므로 잘 보호하고 만료와 폐기를 관리해야 합니다.

단점도 있습니다. 서버가 세션 상태를 유지하므로, 여러 서버에 요청을 나눠 보낸다면 모든 서버가 세션을 함께 볼 수 있도록 Redis 같은 공유 저장소를 쓰거나, 한 사용자의 요청을 같은 서버로 보내는(sticky session) 설정이 필요합니다. 다른 출처 사이의 요청에서는 쿠키가 전송되지 않거나 추가 설정이 필요해 복잡해질 수 있고, 모바일 앱에서는 웹 쿠키를 직접 다루기 어렵습니다.

더 깊이: 세션 쿠키 이름에 붙이는 __Host- 접두사

세션 ID를 담은 쿠키는 HttpOnly, Secure, SameSite 속성만으로는 막기 어려운 공격이 하나 남습니다. 같은 도메인의 다른 하위 도메인이나 HTTP로 열린 페이지가 같은 이름의 쿠키를 먼저 심거나 덮어써, 공격자가 아는 세션 ID를 피해자의 브라우저에 넣는 것입니다. 쿠키 이름의 접두사(cookie prefix)는 이런 덮어쓰기를 브라우저가 거부하게 하는 장치입니다.

이름이 __Secure-로 시작하는 쿠키는 HTTPS 페이지에서 Secure 속성과 함께 설정해야 받아들여집니다. __Host-는 더 엄격해서, 여기에 더해 Domain 속성이 없어야 하고 Path가 /여야 합니다. 그래서 Set-Cookie: __Host-session=값; Secure; HttpOnly; Path=/로 만든 쿠키는 그 쿠키를 설정한 호스트에만 전송되고, 하위 도메인이나 다른 경로에서 같은 이름으로 덮어쓸 수 없습니다. MDN은 이 조합을 출처를 보안의 단위로 다루는 데 가장 가까운 쿠키라고 설명합니다.

조건을 하나라도 어기면 브라우저는 쿠키를 저장하지 않습니다. 예를 들어 Path=/가 빠지거나 Domain=example.com을 적은 __Host- 쿠키는 거부됩니다. 다만 접두사를 지원하지 않는 브라우저에서는 이 확인이 이루어지지 않고 그냥 일반 쿠키로 받아들여지므로, 접두사는 다른 속성을 대신하지 않고 그 위에 더하는 장치입니다. 규칙은 MDN의 Set-Cookie 설명의 쿠키 접두사 항목에 있습니다.

토큰 기반 인증

토큰 기반 인증(token-based authentication)은 SPA, 모바일 앱, 마이크로서비스 등에서 쓰는 방식이며, 대표적인 형식이 JWT(JSON Web Token)입니다. 앱의 종류만으로 어느 방식이 맞는지 정하지 말고, 토큰의 수명과 폐기, 검증 규칙을 비교해 고릅니다.

사용자가 로그인하면 서버는 신원을 확인한 뒤 사용자 ID 같은 정보(payload)를 담고 서버의 키로 서명(signature)한 토큰을 만들어 응답으로 보냅니다. 이런 자체 포함(self-contained) 토큰은 요청마다 세션 기록을 조회하지 않고도 서명을 검증해 확인할 수 있습니다. 클라이언트는 토큰을 저장해 두었다가 요청에 담아 보내는데, 자바스크립트가 읽을 수 있는 곳에 저장해 Authorization: Bearer <token> 헤더에 넣는 방식과, HttpOnly 쿠키에 담아 브라우저가 쿠키로 보내게 하는 방식이 있습니다. 쿠키 방식은 자바스크립트로 토큰을 읽지 않는 대신 CSRF와 쿠키 정책을 따로 챙겨야 합니다. 서버는 받은 토큰의 서명과 만료 시간 등을 검증하고, 유효하면 권한을 확인해 요청을 처리합니다.

이 글에서 다루는 서명된 JWT(JWS 형식)는 Header.Payload.Signature의 세 부분으로 이루어집니다. 헤더에는 토큰의 종류와 서명 알고리즘이, 페이로드에는 사용자 ID와 만료 시간 같은 정보인 클레임(claim)이 들어 있고, 서명은 인코딩한 헤더와 페이로드에 MAC이나 전자 서명을 적용해 내용이 바뀌지 않았는지 검증하게 해 줍니다. 서명은 내용을 감추는 암호화가 아니므로, 페이로드는 누구나 디코딩해 읽을 수 있습니다. 암호화한 JWT(JWE 형식)는 구성이 다르므로 모든 JWT가 세 부분이라고 생각하지는 않습니다.

토큰 방식은 여러 서버가 검증 키만 공유하면 세션 기록 없이 토큰을 검증할 수 있고, 모바일 앱에서도 저장하고 보내기 쉬우며, 프런트엔드와 백엔드가 완전히 나뉜 구조에 잘 맞습니다. Authorization 헤더를 쓰더라도 다른 출처로 보내는 요청은 브라우저의 CORS 검사를 받으므로, 서버가 출처와 헤더를 허락하고 사전 요청(preflight)을 처리해야 합니다.

단점은 토큰이 클라이언트에 있다는 점입니다. 자바스크립트가 읽을 수 있는 곳에 둔 토큰은 XSS 공격으로 탈취될 수 있습니다. 서명만 검증하는 토큰은 따로 폐기를 검사하지 않으면 발급할 때 정한 만료 시간까지 계속 유효하므로, 즉시 무효화해야 한다면 폐기 목록을 두거나, 수명을 짧게 하고 새 토큰을 받는 데 쓰는 리프레시 토큰(refresh token)을 함께 설계해야 합니다. 이런 리프레시와 폐기에는 결국 서버의 상태가 필요할 수 있습니다. 페이로드에 많은 정보를 담으면 토큰이 커져 모든 요청이 무거워지는 점도 주의합니다.

세션과 토큰 비교

세션과 토큰 생명주기 선택 — 상태 추적

세션과 JWT의 발급·전송·검증·로그아웃 뒤 서버/클라이언트 상태가 다르다. 클라이언트 JWT 제거가 복사본 즉시 폐기가 아님을 같은 역할의 상태 변화로 드러낼 가치가 있다.

세션과 JWT는 검증·폐기 책임이 다릅니다

SESSION & SIGNED TOKEN

세션과 JWT는 검증·폐기 책임이 다릅니다

같은 로그인 이후에도 서버 상태를 조회하는 방식과 서명된 클레임을 검증하는 방식의 수명 관리가 다릅니다. 앱 종류만으로 한 방식을 고르지 않습니다.

전송·검증·폐기 책임을 두 수명으로 비교한다8노드6진행관계의두독립수명이다. 세션서버상태조회와JWT서명검증을구별하되JWT에도refresh/폐기상태가필요할수있다. 쿠키와토큰은반대개념이아니다. 마지막JWT클라이언트제거는복사본의즉시폐기가아니며별도서버정책이필요하다. 서명은payload암호화가아니고mobile같다.서버 세션서명된 JWT서버 세션 발급ID ↔ 사용자 상태ID 쿠키 전송Secure·HttpOnlySameSite 정책서버 상태 조회만료·폐기 확인세션 로그아웃서버 레코드 폐기클라이언트 정리서명된 JWT 발급클레임·만료토큰 전송헤더 또는 쿠키각 위협 검토검증 후 인가서명·수명·대상요청 권한 검사JWT 로그아웃클라이언트 제거즉시 폐기는 별도
전송·검증·폐기 책임을 두 수명으로 비교한다8노드6진행관계의두독립수명이다. 세션서버상태조회와JWT서명검증을구별하되JWT에도refresh/폐기상태가필요할수있다. 쿠키와토큰은반대개념이아니다. 마지막JWT클라이언트제거는복사본의즉시폐기가아니며별도서버정책이필요하다. 서명은payload암호화가아니고mobile같다.서버 세션서명된 JWT서버 세션 발급ID ↔ 사용자 상태ID 쿠키 전송Secure·HttpOnlySameSite 정책서버 상태 조회만료·폐기 확인세션 로그아웃서버 레코드 폐기클라이언트 정리서명된 JWT 발급클레임·만료토큰 전송헤더 또는 쿠키각 위협 검토검증 후 인가서명·수명·대상요청 권한 검사JWT 로그아웃클라이언트 제거즉시 폐기는 별도

1 · 서버 세션 발급

로그인 검증 뒤 예측하기 어려운 세션 ID를 만들고 서버의 사용자 상태와 연결합니다.

1 · 서명된 JWT 발급

로그인 검증 뒤 필요한 클레임과 만료를 담아 서명합니다. refresh token은 필요한 설계에서 별도로 발급합니다.

2 · 세션 ID 보관·전송

보통 Secure·HttpOnly·SameSite 쿠키로 전달합니다. HTTPS와 쿠키 범위·credentials 조건을 적용합니다.

2 · JWT 보관·전송

Authorization 헤더 또는 쿠키를 선택합니다. HttpOnly 쿠키는 JS로 읽어 헤더에 넣을 수 없고 브라우저가 쿠키로 전송합니다.

3 · 세션 요청 검증

세션 레코드와 만료·폐기 상태를 조회합니다. 로그인·권한 변경 시 ID를 재발급해 세션 고정을 방지합니다.

3 · JWT 요청 검증

허용 알고리즘·서명·만료·발급자·대상을 검증한 뒤 요청 권한을 검사합니다. refresh를 쓰면 회전·재사용 탐지 정책도 설계합니다.

4 · 세션 로그아웃

서버 레코드를 무효화하고 클라이언트 쿠키도 정리합니다. 유휴·최대 수명 정책을 적용합니다.

4 · JWT 로그아웃

클라이언트 제거만으로 이미 발급된 JWT가 즉시 무효화되지 않습니다. 짧은 만료·폐기 목록·refresh 폐기를 함께 검토합니다.

전송 방식과 위협

쿠키 전송은 CSRF 정책을, JS가 읽을 수 있는 저장소와 헤더 방식은 XSS·토큰 탈취 위험을 검토합니다. HttpOnly도 XSS가 사용자 대신 요청하는 것을 막지는 않습니다.

분산 운영과 서버 상태

세션도 공유 저장소로 여러 서버가 사용할 수 있습니다. JWT도 refresh 회전·즉시 폐기·정책 변경을 관리하면 서버 상태가 필요할 수 있습니다.

여기서는 서명된 JWT를 비교합니다. 서명은 무결성 검증이며 payload 암호화가 아닙니다. 쿠키와 토큰은 서로 반대 개념이 아니며, 토큰을 쿠키로 전달할 수도 있습니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
원도표의 전체 관계·조건·설명
구분내용
전체 관계·조건 설명노드 8개·진행 관계 6개의 두 독립 수명이다. 세션 서버 상태 조회와 JWT 서명 검증을 구별하되 JWT에도 refresh/폐기 상태가 필요할 수 있다. 쿠키와 토큰은 반대 개념이 아니다. 마지막 JWT 클라이언트 제거는 복사본의 즉시 폐기가 아니며 별도 서버 정책이 필요하다. 서명은 payload 암호화가 아니고 mobile도 같다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
로그인 뒤세션: 서버 상태 참조 / JWT: 서명된 credential세션 식별자 또는 서명 토큰이 클라이언트에 있다두 모델의 검증 원천이 다르다
로그아웃 처리세션: 서버 기록 무효 / JWT: 로컬 제거세션은 서버에서 무효화하고 JWT는 로컬 보관본을 지울 수 있다로컬 제거가 복사된 토큰의 폐기를 뜻하지 않는다
다시 제시한 credential세션: 거절 / JWT: 만료/폐기 정책에 따름세션은 무효 기록에 의해 거절되고 JWT는 추가 폐기 정책이 필요하다같은 logout 표시에서도 서버 검증 결과가 다를 수 있다

세션과 토큰 생명주기 선택 — 상태 추적

세션과 JWT의 발급·전송·검증·로그아웃 뒤 서버/클라이언트 상태가 다르다. 클라이언트 JWT 제거가 복사본 즉시 폐기가 아님을 같은 역할의 상태 변화로 드러낼 가치가 있다.

세션과 JWT는 검증·폐기 책임이 다릅니다

SESSION & SIGNED TOKEN

세션과 JWT는 검증·폐기 책임이 다릅니다

같은 로그인 이후에도 서버 상태를 조회하는 방식과 서명된 클레임을 검증하는 방식의 수명 관리가 다릅니다. 앱 종류만으로 한 방식을 고르지 않습니다.

전송·검증·폐기 책임을 두 수명으로 비교한다8노드6진행관계의두독립수명이다. 세션서버상태조회와JWT서명검증을구별하되JWT에도refresh/폐기상태가필요할수있다. 쿠키와토큰은반대개념이아니다. 마지막JWT클라이언트제거는복사본의즉시폐기가아니며별도서버정책이필요하다. 서명은payload암호화가아니고mobile같다.서버 세션서명된 JWT서버 세션 발급ID ↔ 사용자 상태ID 쿠키 전송Secure·HttpOnlySameSite 정책서버 상태 조회만료·폐기 확인세션 로그아웃서버 레코드 폐기클라이언트 정리서명된 JWT 발급클레임·만료토큰 전송헤더 또는 쿠키각 위협 검토검증 후 인가서명·수명·대상요청 권한 검사JWT 로그아웃클라이언트 제거즉시 폐기는 별도
전송·검증·폐기 책임을 두 수명으로 비교한다8노드6진행관계의두독립수명이다. 세션서버상태조회와JWT서명검증을구별하되JWT에도refresh/폐기상태가필요할수있다. 쿠키와토큰은반대개념이아니다. 마지막JWT클라이언트제거는복사본의즉시폐기가아니며별도서버정책이필요하다. 서명은payload암호화가아니고mobile같다.서버 세션서명된 JWT서버 세션 발급ID ↔ 사용자 상태ID 쿠키 전송Secure·HttpOnlySameSite 정책서버 상태 조회만료·폐기 확인세션 로그아웃서버 레코드 폐기클라이언트 정리서명된 JWT 발급클레임·만료토큰 전송헤더 또는 쿠키각 위협 검토검증 후 인가서명·수명·대상요청 권한 검사JWT 로그아웃클라이언트 제거즉시 폐기는 별도

1 · 서버 세션 발급

로그인 검증 뒤 예측하기 어려운 세션 ID를 만들고 서버의 사용자 상태와 연결합니다.

1 · 서명된 JWT 발급

로그인 검증 뒤 필요한 클레임과 만료를 담아 서명합니다. refresh token은 필요한 설계에서 별도로 발급합니다.

2 · 세션 ID 보관·전송

보통 Secure·HttpOnly·SameSite 쿠키로 전달합니다. HTTPS와 쿠키 범위·credentials 조건을 적용합니다.

2 · JWT 보관·전송

Authorization 헤더 또는 쿠키를 선택합니다. HttpOnly 쿠키는 JS로 읽어 헤더에 넣을 수 없고 브라우저가 쿠키로 전송합니다.

3 · 세션 요청 검증

세션 레코드와 만료·폐기 상태를 조회합니다. 로그인·권한 변경 시 ID를 재발급해 세션 고정을 방지합니다.

3 · JWT 요청 검증

허용 알고리즘·서명·만료·발급자·대상을 검증한 뒤 요청 권한을 검사합니다. refresh를 쓰면 회전·재사용 탐지 정책도 설계합니다.

4 · 세션 로그아웃

서버 레코드를 무효화하고 클라이언트 쿠키도 정리합니다. 유휴·최대 수명 정책을 적용합니다.

4 · JWT 로그아웃

클라이언트 제거만으로 이미 발급된 JWT가 즉시 무효화되지 않습니다. 짧은 만료·폐기 목록·refresh 폐기를 함께 검토합니다.

전송 방식과 위협

쿠키 전송은 CSRF 정책을, JS가 읽을 수 있는 저장소와 헤더 방식은 XSS·토큰 탈취 위험을 검토합니다. HttpOnly도 XSS가 사용자 대신 요청하는 것을 막지는 않습니다.

분산 운영과 서버 상태

세션도 공유 저장소로 여러 서버가 사용할 수 있습니다. JWT도 refresh 회전·즉시 폐기·정책 변경을 관리하면 서버 상태가 필요할 수 있습니다.

여기서는 서명된 JWT를 비교합니다. 서명은 무결성 검증이며 payload 암호화가 아닙니다. 쿠키와 토큰은 서로 반대 개념이 아니며, 토큰을 쿠키로 전달할 수도 있습니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.

관계도의 보충 설명

원도표의 전체 관계·조건·설명
구분내용
전체 관계·조건 설명노드 8개·진행 관계 6개의 두 독립 수명이다. 세션 서버 상태 조회와 JWT 서명 검증을 구별하되 JWT에도 refresh/폐기 상태가 필요할 수 있다. 쿠키와 토큰은 반대 개념이 아니다. 마지막 JWT 클라이언트 제거는 복사본의 즉시 폐기가 아니며 별도 서버 정책이 필요하다. 서명은 payload 암호화가 아니고 mobile도 같다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
로그인 뒤세션: 서버 상태 참조 / JWT: 서명된 credential세션 식별자 또는 서명 토큰이 클라이언트에 있다두 모델의 검증 원천이 다르다
로그아웃 처리세션: 서버 기록 무효 / JWT: 로컬 제거세션은 서버에서 무효화하고 JWT는 로컬 보관본을 지울 수 있다로컬 제거가 복사된 토큰의 폐기를 뜻하지 않는다
다시 제시한 credential세션: 거절 / JWT: 만료/폐기 정책에 따름세션은 무효 기록에 의해 거절되고 JWT는 추가 폐기 정책이 필요하다같은 logout 표시에서도 서버 검증 결과가 다를 수 있다

위 그림은 같은 로그인 뒤에도 두 방식의 수명이 어떻게 다른지 나란히 비교합니다. 위쪽의 서버 세션은 로그인을 검증한 뒤 예측하기 어려운 세션 ID를 만들어 서버의 사용자 상태와 연결하고, 보통 Secure, HttpOnly, SameSite 속성을 붙인 쿠키로 보냅니다. 요청이 오면 서버가 세션 기록과 만료, 폐기 상태를 조회하며, 로그인하거나 권한이 바뀔 때는 세션 ID를 새로 발급해 공격자가 미리 정해 둔 ID를 쓰게 하는 세션 고정(session fixation) 공격을 막습니다. 로그아웃하면 서버의 기록을 무효로 하고 쿠키도 지우며, 사용하지 않은 시간과 최대 수명의 정책을 적용합니다.

아래쪽의 서명된 JWT는 로그인을 검증한 뒤 필요한 클레임과 만료 시간을 담아 서명하고, 필요하면 리프레시 토큰을 따로 발급합니다. 토큰은 Authorization 헤더나 쿠키 가운데 하나로 보내는데, HttpOnly 쿠키는 자바스크립트로 읽어 헤더에 넣을 수 없고 브라우저가 쿠키로 보냅니다. 요청이 오면 허락한 알고리즘인지, 서명과 만료 시간, 발급자(issuer)와 대상(audience)이 맞는지 검증한 뒤 권한을 확인하며, 리프레시 토큰을 쓴다면 새로 바꿔 주는 회전(rotation)과 재사용 탐지 규칙도 정합니다. 로그아웃할 때 클라이언트에서 토큰을 지워도 이미 발급된 토큰은 바로 무효가 되지 않으므로, 짧은 만료 시간과 폐기 목록, 리프레시 토큰 폐기를 함께 검토합니다.

그림 아래의 설명은 두 가지를 짚습니다. 쿠키로 보내면 CSRF 정책을, 자바스크립트가 읽을 수 있는 저장소와 헤더로 보내면 XSS와 토큰 탈취 위험을 검토해야 하며, HttpOnly도 XSS 스크립트가 사용자 대신 요청을 보내는 것까지 막지는 못합니다. 또 세션도 공유 저장소로 여러 서버가 쓸 수 있고, JWT도 리프레시 회전이나 즉시 폐기를 관리하려면 서버의 상태가 필요할 수 있습니다. 서명은 내용을 감추는 암호화가 아니며, 토큰을 쿠키에 담아 보낼 수도 있으므로 쿠키와 토큰은 서로 반대되는 개념이 아닙니다.

특징세션 기반 인증토큰 기반 인증 (JWT)
상태 유지서버가 세션 상태를 유지서명으로 검증 가능, 리프레시와 폐기에는 상태가 필요할 수 있음
확장성공유 저장소 같은 세션 공유 설계가 필요검증 키, 수명, 폐기 규칙을 공유해야 함
CORS쿠키와 자격 증명 허락이 필요Authorization 같은 요청 헤더 허락이 필요
모바일 앱상대적으로 어려움쉬움
보안세션 ID도 비밀로 보호하며, 서버가 만료와 폐기를 제어탈취되면 만료까지 위험하므로 폐기 설계가 필요
주로 쓰는 곳전통적인 웹 페이지SPA, 모바일 앱, 마이크로서비스

세션과 JWT는 앱의 종류만으로 고르지 말고, 검증과 폐기, 저장과 전송 방식, 운영에서 필요한 것을 함께 비교해 고릅니다.


권한 부여 방식

인가는 인증된 사용자가 특정 자원에 접근하거나 작업을 할 수 있는지 확인하는 과정입니다. 인증이 누구인지를 확인한다면, 인가는 그 사용자가 이 일을 해도 되는지를 정합니다. 그래서 권한 검사는 인증이 끝난 뒤, 요청이 자원에 닿기 전에 서버에서 해야 합니다. 아래에서는 역할로 권한을 묶는 방식과 여러 속성을 조합하는 방식을 봅니다.

역할 기반 접근 제어

역할 기반 접근 제어(role-based access control, RBAC)는 가장 흔한 인가 방식입니다. 사용자에게 역할(role)을 주고, 역할마다 권한(permission)을 연결해, 사용자가 할 수 있는 일을 역할로 정합니다. 예를 들어 Admin은 게시물 생성, 수정, 삭제, 사용자 관리를 모두 할 수 있고, User는 게시물 생성과 수정을, Guest는 게시물 조회만 할 수 있게 정합니다.

데이터베이스에는 users, roles, permissions 테이블과 이를 잇는 user_roles, role_permissions 같은 중간 테이블을 만들어 관계를 정의합니다. 백엔드에서는 API 엔드포인트에 요청이 오면 그 사용자의 역할이 요청한 작업의 권한을 가졌는지 검사하며, Express에서는 라우트 앞에 권한을 검사하는 미들웨어를 두어 구현합니다.

// app.js 또는 routes/auth.js

// 인증 미들웨어 (JWT 토큰 검증 후 req.user에 사용자 정보 추가)
const authenticateToken = (req, res, next) => {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1]; // Bearer token

    if (token == null) return res.set('WWW-Authenticate', 'Bearer').sendStatus(401); // 토큰 없음

    jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
        if (err) return res.set('WWW-Authenticate', 'Bearer').sendStatus(401); // 유효하지 않은 토큰
        req.user = user; // req.user에 사용자 정보(id, role 등) 저장
        next();
    });
};

// 권한 부여 미들웨어 (특정 역할만 허용)
const authorizeRoles = (roles) => {
    return (req, res, next) => {
        if (!req.user || !roles.includes(req.user.role)) {
            return res.status(403).json({ message: 'Forbidden: You do not have the required role.' });
        }
        next();
    };
};

// 라우트에 미들웨어 적용
app.get('/api/admin-dashboard', authenticateToken, authorizeRoles(['admin']), (req, res) => {
    res.json({ message: 'Welcome to admin dashboard!', user: req.user });
});

app.post('/api/posts', authenticateToken, authorizeRoles(['admin', 'user']), (req, res) => {
    // 게시물 생성 로직
    res.status(201).json({ message: 'Post created.' });
});

검증 함수가 유효한 토큰에서 { id: 7, role: 'user' }를 꺼냈다고 가정해 봅니다. authenticateToken은 이 값을 req.user에 넣고 다음 미들웨어로 넘깁니다. 하지만 authorizeRoles(['admin'])의 목록에 user가 없으므로 관리자 화면 요청은 403으로 끝납니다. 같은 사용자가 게시물을 만들면 ['admin', 'user']를 통과해 핸들러가 201을 보냅니다. 로그인에 성공한 것과 모든 작업이 허락된 것은 서로 다른 판단입니다.

이 코드는 흐름을 보여 주는 간단한 예시라서 jwt와 app의 준비, 토큰 발급, 실제 검증 키와 비밀 관리, 만료와 허락할 알고리즘, 발급자와 대상 같은 검증 규칙을 생략했습니다. authHeader.split(' ')[1]은 앞부분이 Bearer인지나 헤더 전체의 형식을 검사하지 않으므로, 운영 코드로 그대로 옮기면 안 됩니다. 실제로는 JWT 검증 모범 사례(RFC 8725)에 따라 알고리즘과 발급자, 대상을 확인하고, 만료 클레임(exp)의 의미를 설정에 반영해야 합니다. 또 이 코드는 req.user.role만 비교하므로, 게시물을 쓴 사람만 고칠 수 있게 하는 소유자 검사는 따로 필요합니다.

속성 기반 접근 제어

속성 기반 접근 제어(attribute-based access control, ABAC)는 RBAC보다 더 유연하고 세밀한 방식으로, 사용자와 자원, 환경의 여러 속성을 조합해 접근을 결정합니다. “오전 9시부터 오후 5시 사이에만, A 부서의 팀장이 쓴 문서에 접근할 수 있다”거나 “IP 주소가 특정 범위 안일 때만 파일에 접근할 수 있다” 같은 규칙이 예입니다. 아주 세밀하게 제어할 수 있지만 구현하고 관리하기 복잡해서, 주로 규모가 큰 기업 환경에서 씁니다.


비밀번호 보안 다시 보기

인증의 가장 기본이 되는 비밀번호는 앞 글에서 본 원칙을 지켜 저장합니다. 데이터베이스에 저장하기 전에 솔트와 계산 비용을 갖춘 비밀번호 전용 해시를 쓰고, 새 시스템이라면 Argon2id를 먼저 검토하며, 쓸 수 없다면 scrypt 같은 대안을, 기존 시스템과의 호환이 필요하면 bcrypt를 고려합니다.

솔트(salt)는 비밀번호마다 다르게 붙이는 무작위 값으로, 같은 비밀번호라도 다른 해시가 나오게 해 미리 계산해 둔 해시 표로 거꾸로 찾는 레인보우 테이블(rainbow table) 공격을 막습니다. 계산 비용을 높이면 해시를 한 번 계산하는 데 시간이 더 걸려, 무차별 대입 공격으로 많은 비밀번호를 시험하기 어려워집니다.

비밀번호 규칙은 충분한 길이를 요구하고, 유출되었거나 흔한 비밀번호를 막으며, 비밀번호 관리자를 쓸 수 있게 합니다. 특수 문자를 억지로 섞게 하거나 주기적으로 바꾸게 하지 말고, 유출된 정황이 있을 때 바꾸게 하며 그 사용자의 세션도 함께 폐기합니다.


정리

  • 인증은 누구인지 확인하는 일이고, 인가는 그 사용자가 무엇을 할 수 있는지 정하는 일입니다.
  • 보호된 API는 자격 증명이 없거나 유효하지 않으면 401과 WWW-Authenticate로, 인증되었지만 권한이 없으면 403으로 응답합니다.
  • 세션 방식은 서버가 세션 상태를 보관하고 만료와 폐기를 직접 제어하며, 로그인할 때 세션 ID를 새로 발급해 세션 고정을 막습니다.
  • 서명된 JWT는 세션 기록 없이 검증할 수 있지만, 서명은 암호화가 아니고 로그아웃해도 바로 무효가 되지 않으므로 짧은 수명과 폐기를 설계합니다.
  • 토큰을 쿠키로 보내면 CSRF를, 자바스크립트가 읽을 수 있게 두면 XSS와 탈취 위험을 검토해야 합니다.
  • RBAC는 역할로, ABAC는 여러 속성으로 권한을 정하며, 역할 검사와 별개로 대상의 소유자 검사가 필요할 수 있습니다.

연습 문제

1. 미들웨어 순서 따라가기

예제 코드에서 ① 헤더가 없는 요청, ② 검증 함수가 오류를 돌려주는 토큰, ③ 유효한 user의 관리자 화면 요청, ④ 유효한 admin의 게시물 생성 요청이 각각 어디서 끝나고 어떤 상태 코드를 받는지 적어 보세요. ⑤ 헤더를 Basic good-user-token으로 바꿨는데, 검증 함수가 두 번째 값을 유효한 토큰으로 판정했다면 이 코드가 형식 오류를 스스로 잡을까요?

해설 보기

①과 ②는 인가 단계까지 가지 않고 authenticateToken에서 401과 WWW-Authenticate: Bearer를 보냅니다. ③은 인증을 통과하지만 역할 검사에서 403으로 끝납니다. ④는 두 검사를 모두 통과해 게시물 생성 핸들러가 201을 보냅니다.

⑤는 이 코드가 공백으로 나눈 두 번째 값만 꺼내므로 앞부분이 Basic이라는 형식 오류를 놓치고 다음 단계로 넘어갑니다. 이 결과는 토큰이 안전하다는 뜻이 아니라, 헤더를 해석하는 부분을 강화해야 할 지점을 찾은 것입니다. 401의 뜻은 HTTP 명세의 401 Unauthorized에서 확인할 수 있습니다.

2. 페이로드에 담아도 될까

어떤 개발자가 JWT에 서명이 있으니 안전하다며, 페이로드에 사용자의 전화번호와 주소를 넣으려 합니다. 이 판단은 맞을까요?

해설 보기

맞지 않습니다. 서명은 내용이 바뀌지 않았는지 검증할 뿐 내용을 감추지 않으므로, 서명된 JWT의 페이로드는 토큰을 가진 누구나 Base64URL로 디코딩해 읽을 수 있습니다.

페이로드에는 사용자 ID와 만료 시간처럼 검증과 권한 판단에 꼭 필요한 최소한의 정보만 담고, 개인 정보는 서버에서 조회하게 합니다. 내용을 감춰야 한다면 암호화한 JWT(JWE)처럼 다른 방식을 따로 설계해야 합니다. 또 클라이언트에서 토큰을 지워도 다른 곳에 복사된 토큰은 남아 있다는 점도 기억해 둡니다.

3. 남의 게시물 수정

PUT /api/posts/5에 authenticateToken과 authorizeRoles(['admin', 'user'])를 붙였습니다. 5번 게시물은 사용자 3이 썼는데, 사용자 7(role: 'user')이 수정 요청을 보냈습니다. 이 요청은 어떻게 처리될까요? 어떻게 고쳐야 할까요?

해설 보기

두 미들웨어를 모두 통과해 핸들러가 수정을 실행합니다. 역할 검사는 user라는 역할이 게시물을 수정할 수 있는지만 보고, 이 게시물을 쓴 사람이 누구인지는 보지 않기 때문입니다.

핸들러나 별도의 미들웨어에서 게시물을 조회해 작성자 ID가 req.user.id와 같은지, 또는 사용자가 admin인지 확인하고, 아니면 403으로 거부해야 합니다. 역할 기반 검사와 대상의 소유 관계 검사는 서로 다른 권한 판단입니다.

다음 글 웹 성능 최적화 기본 원칙에서는 페이지를 빠르게 만드는 기본 원칙과, 측정을 바탕으로 개선할 곳을 찾는 방법을 살펴봅니다.