반응형
암호화(BCrypt) 및 쿠키(Cookie) 복습 자료
이 문서는 제공된 Java 코드와 학습 노트를 바탕으로 BCrypt를 이용한 비밀번호 암호화와 쿠키를 활용한 로그인 상태 관리 방법을 정리한 복습 자료입니다.
1. 비밀번호 암호화 (BCrypt)
1.1. 암호화 기본 개념
- 정의: 데이터를 보호하기 위해 사람이 이해하기 어려운 형태의 문자(암호문)로 변환하는 과정입니다.
- 목적: 개인정보(특히 비밀번호)를 안전하게 보호하고, 데이터의 무결성을 유지합니다.
- 단방향 암호화: 평문을 암호문으로 변경할 수는 있지만, 암호문을 다시 평문으로 되돌릴 수 없는(복호화 불가) 방식입니다. 비밀번호 저장에 필수적입니다.
1.2. BCrypt란?
- 정의: 비밀번호 저장을 위해 설계된 대표적인 해시 함수 기반의 단방향 암호화 알고리즘입니다.
- 특징:
- 솔트(Salt) 자동 포함: 동일한 비밀번호를 입력해도, 암호화할 때마다 내부에 임의의 값(Salt)을 추가하여 항상 다른 결과의 암호문을 생성합니다. 이로 인해 레인보우 테이블 공격 등을 방어할 수 있습니다.
- 반복 연산(Key Stretching): 암호화/검증 과정을 의도적으로 여러 번 반복하여 처리 속도를 늦춤으로써 무차별 대입 공격(Brute-force attack)에 필요한 시간을 크게 늘립니다.
- 복호화 불가능: 단방향 암호화이므로 암호문을 원본 비밀번호로 되돌릴 수 없습니다.
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);
}반응형
'백엔드 > 스프링' 카테고리의 다른 글
| [Spring] JPA 연관관계 및 참조 복습 (0) | 2025.11.06 |
|---|---|
| [Spring] JPA 실습 복습 자료 (0) | 2025.11.05 |
| [Spring] JWT 토큰과 Security 인증 인가 로직 복습 (0) | 2025.10.22 |
| [Spring] Redis 개념 및 활용법 with Spring Boot (0) | 2025.10.21 |
| [Spring] MyBatis XML 연동 개요 (0) | 2025.10.13 |
| [Spring] 도서 대여 콘셉트 트랜잭션 실습과 피드백 마크다운 (1) | 2025.09.26 |
| [Spring] 13주차+: 마이크로서비스 아키텍처(MSA) 입문 (0) | 2025.09.22 |
| [Spring] 12주차: 설정 분리 및 비동기 처리 (0) | 2025.09.22 |