기존에 만들어놓은 Spring Security 샘플 코드를 사용해서 토이 프로젝트를 진행하고 있는데, Refresh Token 을 클라이언트에게 보내는 방식에서 좀 의문이 생김
기존에 방식은 그냥 로그인하면 Response Body에
{
...
"accessToken": "easdasdasd...",
"refreshToken": "easdwwwwwd..."
}
이렇게 보내고 프론트에서 저장하는 방식을 사용함
근데 이번 프로젝트에서 Access Token을 쿠키나 LocalStorage에 저장해서 사용하는건 알겠는데, Refresh Token 도 클라이언트 측에서 관리하는게 맞을까? 하는 고민이 들었음
그냥 단순히 쿠키에 저장하면 XSS나 CSRF에 위험하지 않을까?
XSS : 해커가 클라이언트 브라우저에 악의적인 JavaScript 코드를 삽입해 클라이언트의 토큰과 같은 개인정보를 탈취함
CSRF : 해커나 공격자가 다른 사이트에서 우리 서비스의 API 요청을 통해 공격하는 것
그래서 클라이언트는 Refresh Token을 사용할 수 없게 백엔드 측에서 Refresh Token에 Http Only 옵션을 달아서 보내줘야 겠다는 방식으로 변경함
→ Http Only는 프론트엔드에서 사용되는 JavaScript 로 쿠키에 접근할 수 없게 만드는 것임. 즉, 쿠키를 가져올 수도, 사용할 수도 없게 하는 것!
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/member")
public class MemberController {
private final AuthService authService;
private final MemberService memberService;
...
@PostMapping("/login")
public ResponseEntity<MemberDto> login(@RequestBody MemberDto memberDto, HttpServletResponse response) {
MemberDto responseMemberDto = authService.login(memberDto);
// create a cookie
Cookie cookie = new Cookie("refreshToken", responseMemberDto.getRefreshToken());
// expires in 1 hours
cookie.setMaxAge(1 * 60 * 60);
// optional properties
cookie.setHttpOnly(true);
cookie.setPath("/");
// add cookie to response
response.addCookie(cookie);
responseMemberDto.setRefreshToken("");
return ResponseEntity.status(HttpStatus.OK).body(responseMemberDto);
}
...
}
그러면 로그인할 때, HttpOnly 상태의 Refresh Token 이 Cookie 로 설정됨
이러면 프론트엔드(=클라이언트)측에선 요청을 보낼 때, JavaScript 를 사용해 Refresh Token을 보낼 수 없게 됨