본문 바로가기
백엔드/스프링

[Spring] 암호화(BCrypt) 및 쿠키(Cookie) 복습 자료

by AI읽어주는남자 2025. 10. 21.
반응형

암호화(BCrypt) 및 쿠키(Cookie) 복습 자료

이 문서는 제공된 Java 코드와 학습 노트를 바탕으로 BCrypt를 이용한 비밀번호 암호화와 쿠키를 활용한 로그인 상태 관리 방법을 정리한 복습 자료입니다.


1. 비밀번호 암호화 (BCrypt)

1.1. 암호화 기본 개념

  • 정의: 데이터를 보호하기 위해 사람이 이해하기 어려운 형태의 문자(암호문)로 변환하는 과정입니다.
  • 목적: 개인정보(특히 비밀번호)를 안전하게 보호하고, 데이터의 무결성을 유지합니다.
  • 단방향 암호화: 평문을 암호문으로 변경할 수는 있지만, 암호문을 다시 평문으로 되돌릴 수 없는(복호화 불가) 방식입니다. 비밀번호 저장에 필수적입니다.

1.2. BCrypt란?

  • 정의: 비밀번호 저장을 위해 설계된 대표적인 해시 함수 기반의 단방향 암호화 알고리즘입니다.
  • 특징:
    1. 솔트(Salt) 자동 포함: 동일한 비밀번호를 입력해도, 암호화할 때마다 내부에 임의의 값(Salt)을 추가하여 항상 다른 결과의 암호문을 생성합니다. 이로 인해 레인보우 테이블 공격 등을 방어할 수 있습니다.
    2. 반복 연산(Key Stretching): 암호화/검증 과정을 의도적으로 여러 번 반복하여 처리 속도를 늦춤으로써 무차별 대입 공격(Brute-force attack)에 필요한 시간을 크게 늘립니다.
    3. 복호화 불가능: 단방향 암호화이므로 암호문을 원본 비밀번호로 되돌릴 수 없습니다.

1.3. Spring Security를 이용한 구현

Step 1: 의존성 추가 (build.gradle)

implementation 'org.springframework.security:spring-security-crypto'

Step 2: BCryptPasswordEncoder 객체 주입

UserService에서 BCryptPasswordEncoder를 주입받아 사용합니다.

// web2.service.UserService.java

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserMapper userMapper;
    // BCryptPasswordEncoder 객체 주입 (또는 직접 생성)
    private final BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
    // ...
}

Step 3: 회원가입 시 암호화 (encode)

사용자가 입력한 평문 비밀번호를 bcrypt.encode() 메소드를 사용하여 암호화하고, 그 결과를 데이터베이스에 저장합니다.

// web2.service.UserService.java

public int signup(UserDto userDto){
    // 평문 비밀번호를 암호화하여 DTO에 다시 설정
    userDto.setUpwd(bcrypt.encode(userDto.getUpwd())); // ex: "1234" -> "$2a$10$..."
    // 암호화된 비밀번호가 DB에 저장됨
    userMapper.signup(userDto);
    return userDto.getUno();
}

Step 4: 로그인 시 비교 (matches)

로그인 시에는 DB에서 가져온 암호문과 사용자가 입력한 평문 비밀번호를 bcrypt.matches() 메소드로 비교합니다. 이 메소드는 내부적으로 평문을 암호화하여 DB의 암호문과 동일한지 검증해줍니다.

중요: 절대 평문.equals(암호문) 또는 encode(평문).equals(암호문) 형태로 비교하면 안 됩니다. (Salt 때문에 항상 false가 나옴)

// web2.service.UserService.java

public UserDto login(UserDto userDto){
    // 1. 아이디로 회원 정보(암호화된 비밀번호 포함)를 가져온다.
    UserDto result = userMapper.login(userDto.getUid());
    if (result == null) return null; // 아이디 없음

    // 2. matches(평문, 암호문)으로 비밀번호 일치 여부 확인
    boolean isMatch = bcrypt.matches(userDto.getUpwd(), result.getUpwd());

    if (isMatch) { // 비밀번호가 일치하면
        result.setUpwd(null); // 보안을 위해 응답 객체에서 비밀번호 제거
        return result;
    } else {
        return null; // 비밀번호 불일치
    }
}

2. 쿠키(Cookie)를 이용한 로그인 상태 관리

2.1. 쿠키 vs 세션

구분 쿠키 (Cookie) 세션 (Session)
저장 위치 클라이언트 (웹 브라우저) 서버
유효 기간 설정된 만료 시간까지 유지 서버 종료 또는 세션 타임아웃 시 삭제
보안 상대적으로 낮음 (탈취 위험) 상대적으로 높음
서버 부하 낮음 사용자가 많아지면 부하 증가
주요 용도 자동 로그인, 장바구니, 사용자 설정 로그인 상태 유지

2.2. 쿠키를 이용한 로그인 흐름

Step 1: 로그인 성공 및 쿠키 생성/전송

로그인에 성공하면 사용자를 식별할 정보(예: uid)를 담은 쿠키를 생성하여 HttpServletResponse에 추가해 클라이언트에게 보냅니다.

// web2.controller.UserController.java

@PostMapping("/login")
public ResponseEntity<?> login (@RequestBody UserDto userDto, HttpServletResponse response) {
   UserDto result = userService.login(userDto);
   if (result != null) { // 로그인 성공 시
       // 1. "loginUser"라는 이름으로 uid를 저장하는 쿠키 생성
       Cookie cookie = new Cookie("loginUser", result.getUid());

       // 2. 쿠키 보안 설정 (필수)
       cookie.setHttpOnly(true); // JavaScript로 쿠키 접근 방지 (XSS 공격 방어)
       cookie.setSecure(false);  // 개발 단계(http)에서는 false, 배포(https)에서는 true로 설정
       cookie.setPath("/");      // 사이트 전체에서 쿠키가 유효하도록 설정
       cookie.setMaxAge(60 * 60); // 쿠키 유효기간 설정 (초 단위, 여기서는 1시간)

       // 3. 응답에 쿠키 추가
       response.addCookie(cookie);
   }
   return ResponseEntity.ok(result);
}

Step 2: 로그인 정보 확인 (마이페이지 등)

서버에 요청이 들어올 때 HttpServletRequest에서 쿠키 배열을 가져와 원하는 쿠키(loginUser)가 있는지, 그 값은 무엇인지 확인하여 로그인 상태를 판단합니다.

// web2.controller.UserController.java

@GetMapping("/myinfo")
public ResponseEntity<?> myInfo (HttpServletRequest request){
    // 1. 요청에 포함된 모든 쿠키 가져오기
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        // 2. 쿠키 배열을 순회하며 "loginUser" 쿠키 찾기
        for (Cookie c : cookies) {
            if (c.getName().equals("loginUser")) {
                String uid = c.getValue(); // 쿠키에 저장된 uid 값 추출
                // 3. uid를 이용해 내 정보 조회
                UserDto result = userService.myInfo(uid);
                return ResponseEntity.ok(result);
            }
        }
    }
    return ResponseEntity.ok(null); // 쿠키가 없으면 비로그인 상태
}

Step 3: 로그아웃 (쿠키 삭제)

쿠키를 삭제하는 표준 API는 없습니다. 대신, 같은 이름의 쿠키를 생성하되 유효 기간(MaxAge)을 0으로 설정하여 클라이언트에게 보내면 브라우저가 해당 쿠키를 즉시 삭제합니다.

// web2.controller.UserController.java

@GetMapping("/logout")
public ResponseEntity<?> logout (HttpServletResponse response) {
    // 1. 삭제할 쿠키와 같은 이름의 쿠키 생성 (값은 null로 설정)
    Cookie cookie = new Cookie("loginUser", null);
    // 2. 유효기간을 0으로 설정하여 즉시 만료시킴
    cookie.setMaxAge(0);
    cookie.setPath("/");
    // 3. 응답에 추가하여 클라이언트에게 보냄
    response.addCookie(cookie);
    return ResponseEntity.ok(true);
}
반응형