icon
13장 : 웹 보안과 성능 최적화

인증과 권한 관리 기초


특정 사용자가 웹 서비스에 접근하여 자신만의 기능을 사용하거나, 특정 리소스에 접근할 수 있도록 허용하는 메커니즘인 인증(Authentication)권한 부여(Authorization) 에 대해 알아볼 차례입니다. 대부분의 웹 애플리케이션은 사용자가 로그인하여 개인화된 경험을 제공하거나, 특정 역할(예: 관리자, 일반 사용자)에 따라 접근 가능한 기능을 제한해야 합니다. 이 과정에서 인증과 권한 관리는 웹 보안의 핵심적인 부분이 됩니다.

이번 장에서는 인증과 권한 부여의 개념을 명확히 구분하고, 웹에서 사용자 인증을 구현하는 주요 방법(세션 기반, 토큰 기반)과 권한 부여를 관리하는 기본 원칙에 대해 상세히 살펴보겠습니다.


인증 vs 권한 부여

이 두 용어는 자주 혼용되지만, 웹 보안에서는 명확히 다른 의미를 가집니다.

  • 인증 (Authentication)

    • 누구인지 확인하는 과정입니다. 사용자가 "너는 누구냐?" 라고 물었을 때, 본인임을 증명하는 과정입니다.
    • 사용자가 주장하는 신원(ID)이 실제와 일치하는지 확인하는 프로세스입니다.
    • 예시: 사용자 ID와 비밀번호를 입력하여 로그인하는 것, 지문 인식, OTP(일회용 비밀번호) 입력 등.
  • 권한 부여 (Authorization)

    • 무엇을 할 수 있는지 결정하는 과정입니다. 사용자가 "너는 무엇을 할 수 있느냐?" 라고 물었을 때, 허용된 작업이 무엇인지 확인하는 과정입니다.
    • 인증된 사용자에게 특정 자원(데이터, 기능)에 대한 접근 권한을 부여하거나 거부하는 프로세스입니다.
    • 예시: 로그인한 사용자가 자신의 프로필을 수정할 수 있는지, 관리자만 특정 게시물을 삭제할 수 있는지, 유료 구독자만 프리미엄 콘텐츠를 볼 수 있는지 등.

요약: 인증은 신원 확인이고, 권한 부여는 허가된 작업의 범위 결정입니다. 인증이 선행되어야 권한 부여가 가능합니다. (신원이 확인되어야 뭘 할 수 있는지 따져볼 수 있으니까요!)


사용자 인증 구현 방식

웹 애플리케이션에서 사용자를 인증하는 대표적인 두 가지 방식이 있습니다.

세션 기반 인증

세션 기반 인증 (Session-based Authentication)은 전통적인 웹 애플리케이션에서 널리 사용되던 방식입니다.

  • 동작 방식

    사용자가 ID와 비밀번호로 로그인 요청을 보냅니다.

    서버는 사용자의 신원을 확인한 후, 고유한 세션 ID(Session ID) 를 생성합니다.

    이 세션 ID는 서버의 메모리나 데이터베이스에 저장되고, 사용자에게는 이 세션 ID를 포함하는 쿠키(Cookie) 를 응답으로 보냅니다.

    클라이언트(브라우저)는 이 쿠키를 저장하고, 이후 모든 요청에 이 쿠키(세션 ID)를 함께 서버로 전송합니다.

    서버는 요청에 포함된 세션 ID를 확인하여, 서버에 저장된 세션 정보와 일치하는지 검증합니다. 일치하면 해당 사용자가 로그인된 것으로 간주하고 요청을 처리합니다.

    로그아웃 시 서버에서 세션 정보를 삭제합니다.

  • 장점
    • 보안성: 세션 ID 자체가 큰 의미를 가지지 않고, 실제 사용자 정보는 서버에 저장되므로 클라이언트 측에 민감한 정보가 노출되지 않습니다.
    • 세션 관리의 용이성 (서버에서 세션 만료, 강제 로그아웃 등 제어).
  • 단점
    • 확장성 (Scalability): 서버에서 세션 상태를 유지해야 하므로, 여러 대의 서버(로드 밸런싱)를 사용하는 경우 모든 서버가 세션 정보를 공유해야 하는 복잡성이 발생합니다 (Sticky Session 또는 Redis와 같은 외부 세션 저장소 필요).
    • CORS (Cross-Origin Resource Sharing) 문제: 다른 도메인 간의 요청 시 쿠키가 전송되지 않거나 보안 제약이 있어 복잡해질 수 있습니다.
    • 모바일 앱 대응 어려움: 모바일 앱에서는 웹 쿠키를 직접 관리하기 어렵습니다.

토큰 기반 인증

토큰 기반 인증 (Token-based Authentication)은 SPA, 모바일 앱, 그리고 마이크로서비스 아키텍처에서 현재 가장 널리 사용되는 방식입니다. 특히 JWT (JSON Web Token) 가 대표적입니다.

  • 동작 방식

    사용자가 ID와 비밀번호로 로그인 요청을 보냅니다.

    서버는 사용자의 신원을 확인한 후, 사용자 정보(payload)를 담고 서버의 비밀 키로 서명(signature)한 토큰(Token) 을 생성합니다. (예: JWT)

    이 토큰을 클라이언트에게 응답으로 보냅니다. 서버는 토큰을 따로 저장하지 않습니다 (무상태성).

    클라이언트(브라우저/앱)는 이 토큰을 로컬 스토리지, 세션 스토리지 또는 쿠키(보안을 위해 HttpOnly 쿠키 권장)에 저장합니다.

    이후 모든 요청 시 HTTP Authorization 헤더에 이 토큰을 포함하여 서버로 전송합니다. (예: Authorization: Bearer <token>)

    서버는 요청에 포함된 토큰의 유효성(서명 검증, 만료 시간 확인 등)을 검증합니다. 토큰이 유효하면 해당 사용자의 권한을 확인하고 요청을 처리합니다.

  • JWT (JSON Web Token): 토큰 기반 인증의 표준 중 하나.
    • 세 부분으로 구성: Header.Payload.Signature
    • Header: 토큰 타입(JWT), 서명 알고리즘(HMAC SHA256 등)
    • Payload: 사용자 ID, 만료 시간 등 실제 정보(클레임)
    • Signature: Header와 Payload를 Base64Url로 인코딩한 값과 서버의 비밀 키를 결합하여 암호화된 서명. 토큰의 무결성(변조 여부)을 검증하는 데 사용됩니다.
  • 장점
    • 확장성 (Scalability): 서버가 클라이언트의 상태를 저장할 필요가 없으므로(Stateless), 여러 서버 간에 부하 분산이 용이하며 서버 확장이 매우 유연합니다.
    • CORS 문제 해소: 토큰은 HTTP 헤더를 통해 전송되므로 쿠키 기반의 CORS 제약에서 자유롭습니다.
    • 모바일 앱 친화적: 모바일 앱에서도 쉽게 토큰을 저장하고 전송할 수 있습니다.
    • 분리된 프론트엔드/백엔드: 프론트엔드와 백엔드가 완전히 분리되어 개발될 때 이상적입니다.
  • 단점
    • 토큰 탈취 위험: 토큰이 클라이언트 측에 저장되므로 XSS 공격 등으로 토큰이 탈취될 경우 보안에 취약해질 수 있습니다. (Local Storage보다는 HttpOnly 쿠키에 저장하는 것이 더 안전함)
    • 토큰 무효화 어려움: 한 번 발행된 토큰은 만료 시간까지 유효하므로, 서버에서 특정 토큰을 강제로 무효화하기 어렵습니다 (블랙리스트 관리 또는 짧은 만료 시간 + Refresh Token 사용).
    • 페이로드 크기: 페이로드에 많은 정보를 담으면 토큰의 크기가 커져 네트워크 트래픽에 영향을 줄 수 있습니다.

세션 vs. 토큰 요약

특징세션 기반 인증토큰 기반 인증 (JWT)
상태 유지서버가 세션 상태 유지 (Stateful)서버가 상태 유지 안 함 (Stateless)
확장성어려움 (세션 공유 필요)용이 (분산 시스템에 적합)
CORS어려움 (쿠키 제약)용이 (헤더를 통해 토큰 전송)
모바일 앱어려움용이
보안세션 ID만 노출, 서버가 제어토큰 탈취 시 위험 (블랙리스트 필요)
주 사용처전통적인 웹 페이지, 단일 서버SPA, 모바일 앱, 마이크로서비스

현대 웹 개발에서는 대부분 토큰 기반 인증을 선호하며, 특히 JWT를 많이 사용합니다.


권한 부여 구현 방식

인증된 사용자가 특정 자원에 접근하거나 특정 작업을 수행할 수 있는지 확인하는 과정입니다.

역할 기반 접근 제어

역할 기반 접근 제어 (RBAC: Role-Based Access Control)은 가장 흔하게 사용되는 권한 부여 방식입니다.

  • 개념: 사용자에게 '역할(Role)'을 부여하고, 각 역할에 특정 '권한(Permission)'을 할당합니다. 사용자는 자신이 가진 역할에 따라 접근 가능한 자원이나 수행 가능한 작업이 결정됩니다.
  • 예시
    • 역할: 관리자(Admin), 일반 사용자(User), 게스트(Guest)
    • 권한: 게시물 생성, 게시물 수정, 게시물 삭제, 사용자 관리
    • Admin 역할은 모든 권한을 가짐.
    • User 역할은 게시물 생성, 게시물 수정 권한을 가짐.
    • Guest 역할은 게시물 조회 권한만 가짐.
  • 구현 방법
    • 데이터베이스: users 테이블, roles 테이블, permissions 테이블, 그리고 이들을 연결하는 중간 테이블(예: user_roles, role_permissions)을 생성하여 관계를 정의합니다.
    • 백엔드 로직: API 엔드포인트에 접근할 때, 요청을 보낸 사용자의 역할을 확인하고, 해당 역할이 요청된 작업에 대한 권한을 가지고 있는지 검사합니다.
      • 예: DELETE /api/posts/:id 엔드포인트에 접근하는 사용자가 Admin 역할인지 확인.
      • Express.js에서는 미들웨어(Middleware)를 사용하여 특정 라우트에 접근하기 전에 권한을 검사하는 로직을 구현할 수 있습니다.

Express.js 권한 미들웨어 예시 (간략)

// 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.sendStatus(401); // 토큰 없음

    jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
        if (err) return res.sendStatus(403); // 유효하지 않은 토큰
        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.' });
});

속성 기반 접근 제어

속성 기반 접근 제어 (ABAC: Attribute-Based Access Control)은 RBAC보다 더 유연하고 세밀한 권한 부여 방식입니다.

  • 개념: 사용자, 자원, 환경 등 다양한 속성(Attribute)을 조합하여 접근 결정을 내립니다.
  • 예시: "오전 9시부터 오후 5시 사이에만 접근 가능한 A 부서의 팀장이 작성한 문서", "IP 주소가 특정 범위 내에 있을 경우만 접근 가능한 파일" 등.
  • 장점: 매우 유연하고 세밀한 제어 가능.
  • 단점: 구현 및 관리가 복잡하여 대규모 엔터프라이즈 환경에서 주로 사용됩니다.

비밀번호 보안 (다시 강조)

인증의 가장 기본적인 요소인 비밀번호 보안은 아무리 강조해도 지나치지 않습니다.

  • 해싱(Hashing): 비밀번호를 데이터베이스에 저장하기 전에 반드시 강력한 단방향 해시 함수(예: bcrypt, scrypt)를 사용하여 해싱해야 합니다.
    • 솔트(Salt): 각 비밀번호마다 고유한 랜덤 값인 솔트를 추가하여 해싱합니다. 이를 통해 동일한 비밀번호라도 다른 해시 값을 가지게 하여 레인보우 테이블 공격 등을 방어할 수 있습니다.
    • 반복 횟수 증가: 해시 함수를 여러 번 반복하여 계산 시간을 늘려 무작위 대입 공격(Brute-force attack)을 어렵게 만듭니다.
  • 비밀번호 정책: 최소 길이, 특수 문자 포함, 대소문자/숫자 조합 등의 복잡성 요구.
  • 재사용 금지: 이전에 사용했던 비밀번호 재사용 금지.
  • 정기적인 변경 권장: 사용자가 주기적으로 비밀번호를 변경하도록 유도.

마무리하며

이번 장에서는 웹 애플리케이션의 사용자 관리에서 가장 중요한 두 가지 개념인 인증(Authentication)권한 부여(Authorization) 의 기초를 학습했습니다.

여러분은 '누구인지 확인하는' 인증과 '무엇을 할 수 있는지 결정하는' 권한 부여의 차이를 명확히 이해했습니다. 또한, 웹에서 사용자를 인증하는 주요 방식인 세션 기반 인증토큰 기반 인증(JWT 포함) 의 동작 원리, 장단점을 비교하여 현대 SPA 및 모바일 앱 개발에서 토큰 기반 인증이 왜 선호되는지 파악했습니다. 마지막으로, 인증된 사용자의 접근 권한을 관리하는 가장 일반적인 방법인 역할 기반 접근 제어(RBAC) 의 개념과 이를 Express.js 미들웨어로 구현하는 간략한 예시를 살펴보았으며, 비밀번호 보안의 중요성을 다시 한번 강조했습니다.

안전한 웹 서비스를 제공하기 위해서는 강력한 인증 시스템과 세밀한 권한 관리 체계를 구축하는 것이 필수적입니다. 이 장에서 배운 지식들을 바탕으로 사용자의 데이터를 보호하고, 안전한 서비스를 제공하는 개발자가 되시길 바랍니다.