인증

인증(Authentication)이란 사용자가 누구인지 신원을 확인하는 과정으로, "너 누구야?"에 대한 검증입니다.

핵심 개념

[현실 세계 비유]
신분증 제시  → 본인 확인    → 인증
출입증 확인  → 출입 가능 여부 → 인가

[웹 서비스]
아이디/비밀번호 입력 → 서버가 본인 확인 → 인증
인증된 사용자가 API 접근 → 권한 확인   → 인가

인증은 항상 인가보다 먼저 수행되며, 인증 없이 인가는 불가능합니다.

인증의 세 가지 요소

요소설명예시
지식 기반 (Something you know)사용자만 아는 정보비밀번호, PIN, 보안 질문
소유 기반 (Something you have)사용자만 가진 물건휴대폰 OTP, 인증서, 보안 카드
속성 기반 (Something you are)사용자의 고유 특성지문, 홍채, 얼굴 인식
[단일 요소 인증]
비밀번호만으로 인증 → 탈취 시 바로 뚫림

[다중 요소 인증 MFA — 2개 이상 조합]
비밀번호(지식) + 휴대폰 OTP(소유) → 하나가 탈취돼도 안전

웹 서비스의 대표적 인증 방식

1. 세션 기반 인증

클라이언트 → 서버: 아이디/비밀번호 전송
서버: DB 조회 → 비밀번호 검증 → 세션 생성
서버 → 클라이언트: Set-Cookie: JSESSIONID=abc123
이후 요청: Cookie: JSESSIONID=abc123 → 서버가 세션 조회로 인증 확인
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest request,
                                     HttpSession session) {
    Member member = memberRepository.findByLoginId(request.getLoginId())
            .orElseThrow(() -> new IllegalArgumentException("사용자 없음"));

    if (!passwordEncoder.matches(request.getPassword(), member.getPassword())) {
        throw new IllegalArgumentException("비밀번호 불일치");
    }

    session.setAttribute("loginMember", member.getId());
    return ResponseEntity.ok("로그인 성공");
}

2. 토큰 기반 인증 (JWT)

클라이언트 → 서버: 아이디/비밀번호 전송
서버: DB 조회 → 비밀번호 검증 → JWT 발급
서버 → 클라이언트: { "accessToken": "eyJhbG..." }
이후 요청: Authorization: Bearer eyJhbG... → 서버가 서명 검증으로 인증 확인
@PostMapping("/login")
public ResponseEntity<TokenResponse> login(@RequestBody LoginRequest request) {
    Member member = memberRepository.findByLoginId(request.getLoginId())
            .orElseThrow(() -> new IllegalArgumentException("사용자 없음"));

    if (!passwordEncoder.matches(request.getPassword(), member.getPassword())) {
        throw new IllegalArgumentException("비밀번호 불일치");
    }

    String token = jwtProvider.createToken(member.getId(), member.getRole());
    return ResponseEntity.ok(new TokenResponse(token));
}

3. OAuth 2.0 (소셜 로그인)

사용자 → 클라이언트: "구글로 로그인"
클라이언트 → 구글: 인증 요청 (리다이렉트)
사용자 → 구글: 구글 아이디/비밀번호 입력
구글 → 클라이언트: 인가 코드 발급
클라이언트 → 구글: 인가 코드로 Access Token 요청
구글 → 클라이언트: Access Token 발급
클라이언트 → 구글 API: Access Token으로 사용자 정보 조회
→ 자체 서비스에서 세션 또는 JWT 발급

직접 비밀번호를 관리하지 않고, 신뢰할 수 있는 제3자(Google, Kakao 등)에게 인증을 위임하는 방식입니다.

인증 방식 비교

항목세션 기반JWT 기반OAuth 2.0
인증 정보 저장서버 (메모리/Redis)클라이언트 (토큰)외부 인증 서버
StatelessXO방식에 따라 다름
서버 확장세션 공유 필요자유로움자유로움
강제 로그아웃쉬움어려움제한적
적합 대상SSR 웹 서비스SPA, 모바일, API소셜 로그인, 서드파티 연동

비밀번호 저장 — 인증의 핵심 보안

// X 절대 하면 안 되는 것 — 평문 저장
member.setPassword("1234");

// O 올바른 방법 — 단방향 해시 저장
member.setPassword(passwordEncoder.encode("1234"));
// → $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

// 검증 시 해시 비교
passwordEncoder.matches("1234", member.getPassword()); // true
[왜 단방향 해시인가]
평문 저장  → DB 유출 시 비밀번호 즉시 노출
양방향 암호화 → 복호화 키가 유출되면 전체 비밀번호 노출
단방향 해시 → 원본 복원 불가 → DB 유출돼도 비밀번호를 알 수 없음

BCrypt는 매번 다른 Salt를 자동 생성하므로
같은 비밀번호도 해시 결과가 매번 다름 → 레인보우 테이블 공격 방어

면접 포인트

CSLOG에서 보기