Next.js에서는 RSC(React Server Component)를 별도 설정 없이 간단하게 사용할 수가 있다.
'use client'
지시어만 컴포넌트 최상단에 추가하지 않으면 그 컴포넌트가 바로 서버 컴포넌트가 되기 때문이다.
이 점을 이용해 클라이언트에서 접근 가능한 로컬 스토리지가 아닌 서버에서만 접근 가능한 쿠키를 통해 Access Token과 Refresh Token을 받아보자!
자바스크립트에서 document.cookie
을 사용하면 모든 쿠키를 확인할 수 있다.
즉, 클라이언트에서 쿠키를 확인할 수 있다.
클라이언트 측 스크립트에서 접근이 불가능하도록 하려면 쿠키를 설정할 때 httpOnly
속성을 ture
로 설정해야 한다.
httpOnly
속성은 웹 애플리케이션의 쿠키를 보다 안전하게 만들기 위해 사용된다.
httpOnly
속성이 true
인 경우 클라이언트 측 스크립트에서 접근할 수 없기 때문에 XSS(Cross-Site Scripting) 공격을 예방할 수 있게 된다.
XSS(Cross-Site Scripting)
: 웹 페이지에 악성 스크립트를 넣어 사용자의 정보를 훔치거나 악성 행동을 하게 만드는 공격
httpOnly
속성만으로는 CSRF(Cross-Site Request Forgery) 공격은 예방하지 못 한다.
CSRF(Cross-Site Request Forgery)
: 웹 페이지에 사용자가 인증된 상태에서 의도치 않은 요청을 전송하도록 속이는 공격
CSRF 공격을 예방하기 위해 쿠키의 SameSite
속성을 Strict
으로 설정할 수 있는데 백엔드 서버 도메인이 클라이언트 도메인과 다르면 쿠키가 전송되지 않아 인증 문제가 발생하게 된다.
백엔드와 클라이언트 도메인이 다른 경우에는 CSRF 토큰을 사용하거나 Referer 헤더 검증을 통해 CSRF 공격을 예방할 수 있다.
CSRF 토큰은 각 요청에 대해 고유한 토큰을 생성하여 검증을 통해 CSRF 공격을 예방한다.
CSRF 토큰은 헤더 말고 폼데이터에 직접적으로 포함하기도 하지만 GET 요청에는 적용하기 어려우므로 헤더에 CSRF 토큰을 설정하는 코드 구현이 추가적으로 필요하더라도 헤더에 넣는 것이 보안에도 좋다.
Referer 헤더 검증은 요청 출처가 올바른지 확인하여 CSRF 공격을 예방한다.
Nest.js와 Next.js로 서비스 로그인 부분을 구현하면서 액세스 토큰과 리프레쉬 토큰을 어디에 저장하면 좋을지 고민했었다.
예전 프로젝트에서는 로컬 스토리지에 저장을 했었는데 클라이언트에서 접근 가능하니까 아무래도 보안에 취약하다 보니 이번 프로젝트에서는 쿠키에 저장하는 방식을 가져가게 되었다!
많은 설정에도 불구하고 쿠키가 탈취될 수도 있으니 클라이언트에서 요청할 때 액세스 토큰 쿠키만 요청 시에 보내도록 추가 설정(액세스 토큰 만료 시에는 리프레시 토큰으로 신규 액세스 토큰 요청)이 필요할 거 같다.