2023. 12. 12. 17:37ㆍ개발/토막난 상식
JWT의 장점은 I/O 작업이 필요없는 빠른 인증 처리였다.
클라이언트가 저장을 어디다 할까?
1. 쿠키 - 작음 문자열만
2. 로컬스토리지 -
3. 세션스토리지
4. 리덕스 스토어
1.
XSS 공격으로부터 localStorage에 비해 안전하다.
쿠키의 httpOnly 옵션을 사용하면 Js에서 쿠키에 접근 자체가 불가능하다.
그래서 XSS 공격으로 쿠키 정보를 탈취할 수 없다.
(httpOnly 옵션은 서버에서 설정할 수 있음)
하지만 XSS 공격으로부터 완전히 안전한 것은 아니다.
httpOnly 옵션으로 쿠키의 내용을 볼 수 없다 해도
js로 request를 보낼 수 있으므로 자동으로 request에 실리는 쿠키의 특성 상
사용자의 컴퓨터에서 요청을 위조할 수 있기 때문.
공격자가 귀찮을 뿐이지 XSS가 뚫린다면 httpOnly cookie도 안전하진 않다.
CSRF 공격에 취약하다.
자동으로 http request에 담아서 보내기 때문에
공격자가 request url만 안다면
사용자가 관련 link를 클릭하도록 유도하여 request를 위조하기 쉽다.
2.
CSRF 공격에는 안전하다.
그 이유는 자동으로 request에 담기는 쿠키와는 다르게
js 코드에 의해 헤더에 담기므로 XSS를 뚫지 않는 이상
공격자가 정상적인 사용자인 척 request를 보내기가 어렵다.
XSS에 취약하다.
공격자가 localStorage에 접근하는 Js 코드 한 줄만 주입하면
localStorage를 공격자가 내 집처럼 드나들 수 있다.
3 - 창끄면 사라짐 구지?
4- 새로고침하면 사라짐
2. XSS(Cross Site Scripting)
XSS라고 불리는 이유는 CSS가 이미 약자가 있기 때문이고
code injection attack이라고도 한다.
XSS도 다양한 공격 방법이 있는데 우선은
공격자가 의도하는 악의적인 js 코드를 피해자 웹 브라우저에서 실행시키는 것
정도로 알고 있으면 된다.
이 방법으로 피해자 브라우저에 저장된 중요 정보들을 탈취 가능하다.
3. CSRF(Cross Site Request Forgery)
정상적인 request를 가로채 피해자인 척 하고 백엔드 서버에
변조된 request를 보내 악의적인 동작을
수행하는 공격을 의미한다. (피해자 정보 수정, 정보 열람)
안전할려면?
refresh token
백엔드 api 개발자와 소통이 가능하다면
refresh token을 httpOnly 쿠키로 설정하고
url이 새로고침 될 때마다 refresh token을 request에 담아
새로운 accessToken을 발급 받는다.
발급 받은 accessToken은 js private variable에 저장한다.
이런 방식을 사용하는 경우,
refresh token이 CSRF에 의해 사용된다 하더라도
공격자는 accessToken을 알 수 없다.
CSRF는 피해자의 컴퓨터를 제어할 수 있는 것이 아니기 때문이다.
요청을 위조하여 피해자가 의도하지 않은
서버 동작을 일으키는 공격방법이기 때문에
refresh token을 통해 받아온 response(accessToken)는
공격자가 확인할 수 없다.
따라서 쿠키를 사용하여 XSS를 막고
refresh token 방식을 이용하여 CSRF를 막을 수 있다.
클라이언트가 로그인할 때 Access Token 및 Refresh Token을 발급해주는 방법이다.
Refresh Token은 Access Token보다 만료 기한이 긴 토큰이다.
클라이언트가 요청을 보냈는데 Access Token이 만료되었을 때, Refresh Token을 이용하여 Access Token의 재발급을 요청한다.
이때 서버는 DB에 저장된 Refresh Token과 비교하여 유효하면 Access Token을 발급한다.
만약 Refresh Token도 만료된 경우라면 사용자에게 로그인을 요구한다.
이 전략을 사용하면 Access Token의 만료 기한을 짧게 설정하여 위의 짧은 만료 기한 설정 전략처럼 탈취되더라도 빠르게 만료될 수 있다. 또한 짧은 만료 기한에도 불구하고 자주 로그인을 할 필요가 없어진다. 서버가 강제로 Refresh Token을 만료시킬 수도 있다.
하지만 이렇게 완벽하게 보이는 Refresh Token 발급 방법도 단점은 있다. Refresh Token 검증을 위해 DB(혹은 별도의 저장소)에 저장해야 하고, 자원이 소요될 뿐더러 추가적인 I/O 작업이 발생한다. (JWT의 장점은 I/O 작업이 필요없는 빠른 인증 처리였다.)
재발급토큰이 공격자에게 탈취될 경우, 해당 공격자가, 토큰을 계속 refresh하여 사실상 기한제한 없이 로그인을 유지할 수 있다는 단점이있어요.
따라서 이를 막기위해, refresh토큰의 payload를 캐시서버 또는 세션 스토리지에 저장한 후
refresh 요청시 서버측에 저장된 refresh토큰의 payload와 일치여부를 검사하는 방식이에요.
이를 통해서, 사용자가 로그아웃하거나 공격자에게 토큰을 탈취당해, refresh를 막아야 할 경우
서버측에 저장된 refresh 토큰의 payload를 제거하여 추후 refresh 요청시 검사를 실패하도록 방식이에요.
세션과는 다르게, redis에 저장된 payload만으로는 tokenizing 할 수 없어서 redis server 데이터가 유출되더라도, 클라이언트로의 위장이 불가능해요. 다만 세션과 마찬가지로 부하가 걸릴 가능성은 존재해요.
- Access Token이 만료될 때 마다 새롭게 발급하는 과정에서 생기는 HTTP 요청 횟수가 많다. 이는 서버의 자원 낭비로 이어질수 있다.
취사선택 도움
CSRF 공격은 다루기 쉬운 반면 프론트엔드 크기가 크면 클수록
XSS 공격을 막기위한 작업은 많아지므로 쿠키 사용을 추천한다고 한다.
쿠키는 별도로 헤더에 담지 않아도 요청을 보낼때 자동으로 담아서 보내지기 때문에
매번 서버로의 요청에 담아야하는 토큰이라는 성격과 잘 맞고, 코드도 더 간결하게 작성할 수 있게 되는것같아요
vs
- cookie의 httpOnly 옵션도 XSS 공격을 완벽히 막을 수 없다.
어차피 XSS 방어는 필수적이므로 cookie의 장점이
매력적이게 보이지 않는다. - cookie를 사용한다면 백엔드 api에 내가 사용하는 cookie를 위한
설정을 요구해야한다.
백엔드와 조율이 잘 되는 상태면 cookie를 사용해도 문제 없지만
서드파티 api의 경우 거의 불가능하므로 localStorage가 더 좋을 것 같다. - mdn은 저장소로 쿠키를 추천하지 않는다. 대신 ModernStorage(localStorage와 sessionStorage)를 추천한다.
Refresh Token의 휴효기간이 만료 됐다면, 사용자는 새로 로그인 해야한다. Refresh Token도 탈취될 가능성이 있기때문에 적절한 유효기간 설정이 필요하다.(보통 2주)
- 사용자가 ID, PW를 통해 로그인
- 서버에서는 회원 DB에서 값을 비교한다.(보통 PW는 일반적으로 암호화해서 들어간다.)
- 사용자 인증이 되면 서버에서 Access Token, Refresh Token을 발급, 보통 회원 DB에 Refresh Token을 저장해준다.
- 서버는 사용자에게 Access Token, Refresh Token 을 보낸다.
- 사용자는 Refresh Tokendms 은 안전한 저장소에 저장 후, Access Token을 헤더에 실어 요청을 보낸다.
- 서버는 Access Token을 검증 후
- 이에 맞는 데이터를 사용자에게 보내준다.
- 시간이 흘러 Access Tokendl 만료
- 사용자는 만료된 Access Token을 헤더에 실어 요청을 보낸다.
- 서버는 Access Token이 만료된을 확인
- 만료된 토큰임을 알리고 권한없음을 신호로 보낸다.
Access Token이 만료될때 마다 9~11 과정을 거칠 필요는 없다. Access Token의 Payload를 통해 유효기간을 알수 있다.
따라서 프론트엔드 단에서 API 요청 전에 토큰이 만료 됐다면 바로 재발급 요청 가능. - 사용자는 Refresh Token과 Access Token을 함께 서버로 보낸다.
- 서버는 받은 Access Token이 조작되지 않았는지 확인한후, Refresh Token과 사용자의 DB에 저장되어 있던 Refresh Token을 비교한다.
- 서버는 Token이 동일하고 유효기간도 지나지 않았다면 새로운 Access Token을 사용자에게 보내준다.
- 새로운 Access Token을 헤더에 실어 API 요청을 한다.
결론,,,
역시 보안은 기찮고 돈 많이 들수록 좋아진다.
'개발 > 토막난 상식' 카테고리의 다른 글
ESLint: 'eslint'의 경로를 지정하세요. 파이참 (0) | 2023.12.15 |
---|---|
깃허브 유저별 작성한 라인수 확인 (0) | 2023.12.15 |
로그인을 구현해 봅시다 (0) | 2023.12.12 |
jwt 저장 위치 좋은글 (0) | 2023.12.11 |
딥하게 React 작동원리 파보기 (0) | 2023.12.07 |