홈으로 돌아가기

Rust에서의 인가 서비스 개발: 토큰, 암호화, Redis

이 기사는 Rust에서의 인가 서비스 개발에 전념하며, JWT 및 불투명 토큰 생성, 비대칭 암호화를 사용한 검증, Redis 저장을 다룹니다. 자료에는 실전 코드 예제와 잠재적 취약점 논의가 포함됩니다.

Rust에서 인가 서비스 구축 방법: 기초부터 고급 기법까지
Advertisement 728x90

# 안전한 Rust 인증 서비스 구축: 토큰, 암호화, Redis

Rust로 견고한 인증 서비스를 만드는 데는 암호학, 토큰 관리, 그리고 영리한 추상화에 대한 탄탄한 이해가 필요합니다. 이 글에서는 JWT와 불투명 토큰 생성, 검증, Redis 저장을 다루며 실전 경험을 공유합니다.

토큰 아키텍처와 생성

서비스는 두 가지 토큰 유형을 사용합니다: 짧은 세션을 위한 액세스 토큰(JWT)과 재인증 없이 원활한 갱신을 위한 리프레시 토큰(불투명 토큰).

JWT 토큰은 RS256 알고리즘으로 비대칭 암호화를 사용하며, 서명에는 개인 키, 검증에는 공개 키가 필요합니다. 불투명 토큰은 클라이언트가 읽을 수 없는 무작위 base64 문자열로, 보안을 강화합니다.

Google AdInline article slot

키 생성 구성 요소

  • JwtTokenProvider: 클레임과 개인 키를 사용한 JWT 생성 트레이트.
  • OpaqueTokenProvider: 무작위 바이트를 통한 불투명 토큰 트레이트.
  • Claims 구조체: sub(사용자 ID), jti(토큰 ID), iat(발급 시각), exp(만료 시각) 등의 표준 필드 포함.

JwtTokenProvider 구현 예시:

pub trait IJwtTokenProvider {
    type Claims: Send + Sync;
    type Error;
    fn generate(&self, claims: &Self::Claims, pem: &str) -> Result<String, Self::Error>;
}

토큰 검증과 유효성 검사

JWT 검증은 공개 키를 사용해 유출된 개인 키를 차단합니다. IJwtTokenValidator 트레이트가 서명 검사와 토큰 무결성을 처리합니다.

검증 주요 포인트

  • PEM 형식: PEM 파일에 키 저장, 인증서와 신뢰 체인 지원.
  • 암호화 알고리즘: 대칭(예: HS256)과 비대칭(예: RS256) 지원, 후자를 보안상 선호.
  • 클레임 변환: 라이브러리 호환성을 위해 도메인 클레임 모델을 DateTime에서 usize로 변환 등.

검증 코드 예시:

Google AdInline article slot
pub trait IJwtTokenValidator {
    type Claims: Send + Sync;
    type Error;
    fn verify(&self, token: &str, pem: &str) -> Result<Self::Claims, Self::Error>;
}

토큰 저장과 오케스트레이션

TokenManager와 KeyManager가 토큰과 키를 관리합니다. TokenManager는 생성, 검증, Redis 저장을 유연한 추상화로 처리합니다.

RedisIO 구현

RedisIO는 setex, get, delete 메서드로 저장 작업을 단순화해 보일러플레이트를 줄이고 가독성을 높입니다.

예시:

Google AdInline article slot
impl<Storage> RedisIO<Storage>
where Storage: redis::AsyncCommands + Send + Sync
{
    pub async fn setex(&mut self, key: &str, data: &str, exp: u64) -> Result<(), redis::RedisError> {
        self.redis_storage.set_ex::<&str, String, (>(&key, data.to_string(), exp).await?;
        Ok(())
    }
}

TokenManager 기능

제네릭으로 제공자와 검증기를 사용해 쉽게 교체 가능. 주요 메서드:

  • generate_pair: 액세스/리프레시 쌍 생성, Redis에 TTL과 함께 저장.
  • verify_access: 액세스 토큰 존재와 무결성 검증.

사용 예시:

pub async fn generate_pair(&mut self, claims: &Claims, pem: &str) -> Result<(String, String), TokenManagerError> {
    let access_token = self.access_provider.generate(&claims, &pem)?;
    let refresh_token = self.refresh_provider.generate();
    // Redis 저장 로직
    Ok((access_token, refresh_token))
}

주요 요점

  • JWT에 RS256 비대칭 암호화가 대칭 방식보다 보안 우수.
  • 불투명 토큰은 무작위 base64 문자열로 위조 방지.
  • 트레이트로 테스트와 교체 용이.
  • Redis TTL 저장으로 세션 효율 관리, DB 부하 감소.
  • 개인/공개 키 엄격 분리로 침해 방지.

흔한 함정과 해결책

개발 중 발견된 문제:

  • Base64 팽창: 32바이트가 43바이트로 늘어 저장 오류 발생 가능.
  • 키 오용: 검증에 개인 키 사용 금지.
  • 타입 불일치: DateTime을 usize로 변환 시 유효성 검사 필요.

해결책:

  • 다양한 데이터 크기로 엣지 케이스 테스트.
  • 키 타입/형식 엄격 검사.
  • 검증된 JWT/암호화 라이브러리 활용.

— Editorial Team

Advertisement 728x90

다음 읽기