JWT 토큰을 안전하게 사용하자 - 1 쿠키생성하기

hanana·2024년 2월 19일
1
post-custom-banner

로그인 요청이 들어오면 응답으로 accessToken, refreshToken을 반환해주고
이를 localstorage에 저장하는 방식으로 구현했었다.

react

axios({
  method: "post", // [요청 타입]
  url: process.env.REACT_APP_BASE_URL + '/token/login', // [요청 주소]
  data: reqBody, // [요청 데이터]
  headers: {
    // 'Content-Type': 'multipart/form-data'
  }, 
  //timeout: 5000 // [타임 아웃 시간]
  //responseType: "json" // [응답 데이터 : stream , json]
})
  .then(function (response) {
    const data = response.data;
    const accessToken = data.accessToken;
    const refreshToken = data.refreshToken;
    localStorage.setItem('access', accessToken);
    localStorage.setItem('refresh', refreshToken);
    // 생략

spring

public TokenInfo generateToken(Authentication authentication) {
    // 권한 가져오기
    String accessToken = getAccessToken(authentication);
    // Refresh Token 생성
    String refreshToken = getRefreshToken(authentication.getName())
    
    return TokenInfo.builder()
            .grantType("Bearer")
            .accessToken(accessToken)
            .refreshToken(refreshToken)
            .build();
}

그러나, 여러 문서를 확인한 결과
이렇게 AccsccToken과 RefreshToken을 함께 localstorage에 저장하게 되면
XSS 공격에 취약하며(자바스크립트 코드 한줄로 토큰 탈취가능), 보안상에 좋지 않다는 이야기가 나와서
RefreshToken을 httpOnly속성의 쿠키로 옮기려고 한다.

시도1.

BackendServer에서 쿠키를 생성해주고 return 하기
로그인 요청시 응답을 해주는 코드를 다음과 같이 바꿨다.

public TokenInfo generateToken(Authentication authentication, HttpServletResponse response) {
    // 권한 가져오기
    String accessToken = getAccessToken(authentication);
    // Refresh Token 생성
    String refreshToken = getRefreshToken(authentication.getName())
    
    refreshTokenInfoCookie(response, refreshToken); // 추가
    
    return TokenInfo.builder()
            .grantType("Bearer")
            .accessToken(accessToken) // refresh토큰 제거
            .build();
}

// 추가
private static void refreshTokenInfoCookie(HttpServletResponse response, String refreshToken) {
    Cookie refreshTokenCookie = new Cookie("refreshToken", refreshToken);
    refreshTokenCookie.setHttpOnly(true);
    refreshTokenCookie.setMaxAge(3600 * 24); // 24시간
    refreshTokenCookie.setPath("/");
    response.addCookie(refreshTokenCookie);
}

결과


쿠키가 없다....!!

추측컨데
쿠키를 생성받아서 저장하고 있는 클라이언트는 back-end 서버이고
현재 사용하고 있는 클라이언트는 front-end 서버여서
서버에서 쿠키를 생성한들 클라이언트까지 도달하지 않는것처럼 보인다.

가 아니라

응답 헤더에는 정상적으로 쿠키를 생성해서 전달해주나,
axios에서 받는 과정에서 후처리가 부족했던것처럼 보인다.


번외. 삽질일기

npm install react-cookie 명령어를 통해 react환경에서 cookie를 사용할 수 있게 만들어준다.
서버의 응답을 바탕으로 쿠키를 생성하였다.
이때 httpOnly 속성을 사용하면
개발자도구에서 나타나지 않았다.

const [cookies, setCookie] = useCookies(['refresh','babo']);


  .then(function (response) {
    const data = response.data;
    const accessToken = data.accessToken;
    const refreshToken = data.refreshToken;
    localStorage.setItem('access', accessToken);
    // refresh token - 
    setCookie('refresh', refreshToken,
      {
        path: "/",
        httpOnly: false, // todo true로 변경
        secure: true,
        sameSite: "None"
      }
    );
    setCookie('babo','babo')
    // refresh token - end

처음에는 HttpOnly 속성이라 단순히 개발자도구에서 나타나지 않았을 것이라고 생각하였으나
프론트엔드에서 쿠키를 생성하는것 자체가 자바스크립트로 진행되는 것이기 때문에
httpOnly 속성의 쿠키는 Backend 서버에서 내려주어야 한다고 한다


글이 길어져서 다음 포스팅에서 이어집니다..!


참고
https://okky.kr/questions/1448836

profile
성숙해지려고 노력하지 않으면 성숙하기까지 매우 많은 시간이 걸린다.
post-custom-banner

0개의 댓글