학습 정리 - 브라우저 저장소 보안과 axios 인터셉터 (2025.05.02)

수아·2025년 5월 2일
0

학습 정리

목록 보기
51/51
post-thumbnail

회고 리스트

1. localStorage와 sessionStorage 차이점에 대하여 설명하시오.

항목localStoragesessionStorage
유지 기간브라우저를 닫아도 남아 있음 (영구)브라우저 탭을 닫으면 삭제됨 (세션 단위)
저장 위치클라이언트 브라우저 내 저장소클라이언트 브라우저 내 저장소
접근 방식자바스크립트로 직접 접근 (window.localStorage)자바스크립트로 직접 접근 (window.sessionStorage)
용도장기 저장 (예: 자동 로그인 유지)임시 저장 (예: 한 세션 내 상태 유지)
보안XSS 취약XSS 여전히 취약

2. 쿠키 저장소에 대하여 설명하시오.

쿠키는 클라이언트가 저장하고 서버로 자동 전송되는 작은 데이터 조각이다.
HTTP 요청 시 자동으로 서버에 함께 전송된다.
주로 로그인 유지, 세션 정보, 사용자 설정 등을 저장하는 데 사용된다.
HttpOnly, Secure, SameSite 옵션을 통해 보안 설정이 가능하다.
용량 제한이 있고 너무 많은 데이터 저장에는 적합하지 않다.

3. 보안에 관련된 내용입니다. (면접때 물을 수 있어 정리 한번 해드립니다.)

  • 실무에서 꼭 아래와 같이 하는건 아니오니, 참고 부탁드리겠습니다.
저장소 종류보안 등급권장 여부설명
localStorage낮음❌ 사용 권장 X자바스크립트로 접근 가능하여 XSS에 매우 취약함. 특히 access token을 저장하면 위험함.
sessionStorage중간⚠️ 상황에 따라localStorage보다 범위가 좁고 탭을 닫으면 초기화되지만 여전히 자바스크립트로 접근 가능하므로 XSS에 노출됨.
cookie (HttpOnly)높음✅ 권장HttpOnly 옵션을 사용하면 자바스크립트 접근 불가 → XSS 방지. 단 CSRF 공격에는 취약할 수 있어 SameSite 옵션 설정 필요.
Memory only높음✅ (SPA에서)리렌더링 또는 새로고침 시 초기화됨. 가장 안전하지만 상태 관리 어려움. access token은 매번 재요청해야 함. 보안은 높지만 UX엔 제약이 생김.

4. axios 에서 interceptor 함수와 사용 용도에 대하여 설명하시오.

인터셉터(interceptor)는 요청(Request) 또는 응답(Response)이 실제로 서버와 오고 가기 전에 axios가 가로채서 공통 로직을 삽입할 수 있는 전처리기이다.

모든 요청에 공통적인 작업(예: 요청 헤더에 access token 자동으로 넣기)을 추가할 수 있고 모든 응답에 대한 공통 처리(예 : 응답이 401(토큰 만료)이면 자동으로 refresh 요청 보내기)도 가능하기 때문에 사용한다.

구분역할예시
요청 인터셉터서버에 요청 보내기 전에 조작토큰 넣기, 언어 설정 등
응답 인터셉터서버 응답 받은 후 가공에러 처리, 토큰 갱신, 공통 응답 포맷 가공 등

- 요청 인터셉터

: 서버에 요청이 보내지기 전에 동작
: 용도는 access token 자동 추가, 언어 설정, 공통 헤더 설정

- 응답 인터셉터

: 응답이 도착한 뒤 처리
: 용도는 401 에러 시 자동으로 refresh 요청, 공통 에러 처리, 응답 포맷 가공

401 Unauthorized 에러

일반적으로 인증이 실패했을 때 발생하는데 대표적인 경우가 바로 Access Token의 유효 기간이 만료되었을 때이다.

실무에선 401 에러 발생 시 보통 refresh 토큰으로 새로운 access 토큰을 요청하고 요청 실패 시 로그아웃 처리한다.

// 요청 인터셉터: access token 자동 첨부
axios.interceptors.request.use((config) => {
  const access = localStorage.getItem("access");
  if (access) {
    config.headers.Authorization = `Bearer ${access}`;
  }
  return config;
});


// 응답 인터셉터: access token 만료 시 refresh로 재발급 요청
axios.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response.status === 401) {
      const originalRequest = error.config;
      
      // access token이 만료되었고 아직 재시도 안 했을 경우
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;

      try {
        const refresh = localStorage.getItem("refresh");
        
        // refresh token으로 새로운 access token 요청
        const res = await axios.post("http://localhost:8000/api/auth/jwt/refresh/", {
          refresh: refresh,
        });

        const newAccess = res.data.access;
        localStorage.setItem("access", newAccess);

        // 새 access token으로 Authorization 헤더 갱신
        originalRequest.headers.Authorization = `Bearer ${newAccess}`;

        // 요청 재시도
        return axios(originalRequest);
      } catch (refreshError) {
        console.error("❌ 토큰 재발급 실패", refreshError);

        // refresh token도 만료되었을 경우: 로그아웃 처리
        localStorage.removeItem("access");
        localStorage.removeItem("refresh");
        window.location.href = "/login";  // 로그인 페이지로 이동
      }
    }

    return Promise.reject(error);
  }
);

0개의 댓글