거의 알고리즘 일기장
jwt 로그인 방식 본문
프로젝트에 로그인을 붙일 일이 생겼다.
나는 jwt 방식을 선택했는데, 왜 선택하였는지에 대해 공유하고자 한다.
1. jwt란 ?
jwt는 json web token의 약어로 인증 방식 중 하나이다.
사용 방법으로는 서버와 클라이언트 간 정보를 주고 받을 때 Http 리퀘스트 헤더에 JSON 토큰을 넣은 후 서버는 별도의 인증 과정없이 헤더에 포함되어 있는 JWT 정보를 통해 인증한다.
2. 필요 사전 지식 <- 블로그 글 참조 (https://velog.io/@yaytomato/프론트에서-안전하게-로그인-처리하기)
1) json ( js object notation ) :
key value 형식의 js object 표현식, 원래 xml형식의 데이터로 보내고 받았으나 xml 형식은 사람이 알아보기 힘들다는 단점때문에 데이터 형식을 json 형식으로 많이 쓰게 됨.
2) 로그인의 방식 :
문제점 :
😈 : 전통적으로 쓰는 세션 id를 이용한 로그인 방식은 요즘과 같이 여러서버를 사용하는 형태 ( 로드밸런서 등 ) 에서는 별도의 처리를 하지 않는다면 세션 id를 발행한 서버가 아닌 서버로 요청이 들어오게 된다면 인증이 안될수도 있고, 별도의 처리 과정도 db에 세션 id를 저장해두고 계속 찾아오는 형태로 매우 귀찮은 구조가 될수 있기 때문이다.
😈 : 보안 문제 상으로도 세션 id를 브라우저에 저장하는 방식은 어떤 방식이던지 보안 위험요소가 있다.
3) 브라우저 저장소 & 보안 이슈 :
- localStorage 방식
브라우저 저장소에 저장하는 방식, js의 글로벌 변수로 읽기/ 쓰기 접근 가능
😈 : localStorage는 글로벌 변수로 읽기 쓰기가 가능하기 때문에 xss를 이용해서 그 안에 있는 세션 id, refreshToken, accessToken을 가져오거나, 그 값을 이용해서 api 콜을 위조 가능 - 쿠키 저장 방식
브라우저에 쿠키로 저장하면, 클라이언트가 HTTP 요청을 보낼시에 자동으로 쿠키가 서버에 전송된다. js 내 글로벌 변수로 읽기, 쓰기가 가능
😇 : 쿠키에 refreshToken만 저장하고 새로운 accessToken을 받아와 인증에 이용하는 구조에서는 CSRF 취약점 공격을 방어할수 있다. refreshToken로 accessToken을 받아도 xss이슈가 없다면 이를 이용해서 유저 정보를 가져올수 없기 때문
😈 : localStorage 방식처럼 값들을 불러오거나, api 콜을 보내면 쿠키에 담긴 값을 이용해서 api 콜 위조 가능
😈 : CSRF 취약점이 존재한다면, 인증 정보가 쿠키에 담겨 서버로 보내지기 때문에 이를 이용해서 액션 수행 가능 - secure, httpOnly 쿠키 저장 방식
브라우저에 쿠키로 저장되긴 하지만, js내에서 접근이 불가능하다. secure을 적용하면 https 접속에서만 동작한다.
😇 : httpOnly 쿠키 방식으로 저장된 정보는 XSS 취약점 공격으로 담긴 값을 불러올 수 없다.
😇 : httpOnly 쿠키 역시 refreshToken만 저장하고 accessToken을 받아와 인증에 이용하는 구조로 CSRF 공격 방어가 가능하다.
😈 : 쿠키 저장 방식과 같은 이유로 세션 id, accessToken은 저장하면 안 된다.
😈 : httpOnly 쿠키에 담긴 값에 접근할 수는 없지만 XSS 취약점을 노려 API 콜을 요청하면 httpOnly 쿠키에 담긴 값들도 함께 보내져 유저인 척 정보를 빼오거나 액션을 수행할 수 있다
어떤 저장 방식을 택해도 XSS 취약점이 있다면 보안 이슈가 존재한다 (XSS로 API 콜을 보내는 방식으로 다 뚫린다). 그러므로 유저 정보 저장 방식을 바꾸는 것만으로는 방어할 수 없고, 클라이언트와 서버에서 추가적으로 XSS 방어 처리가 필수다.
ex) <input>에서 입력된 값이 html / Javascript로 인식되지 않도록 서버에서 escape 처리를 해준다. 또 url을 통해 Javascript를 수행할 수 없도록 라우팅을 꼼꼼하게 관리한다. 다행인 것은 React는 공격자가 string에 html / Javascript를 담아 JSX에 삽입할 경우 자동으로 escape 처리한다.
4) 보안 공격 :
- XSS 공격 공격자(해커)가 클라이언트 브라우저에 Javascript를 삽입해 실행하는 공격이다.
공격자가 <input>을 통해 Javascript를 서버로 전송해 서버에서 스크립트를 실행하거나, url에 Javascript를 적어 클라이언트에서 스크립트 실행이 가능하다면 공격자가 사이트에 스크립트를 삽입해 XSS 공격을 할 수 있다. 이때 공격자는 Javascript를 통해 사이트의 글로벌 변숫값을 가져오거나 그 값을 이용해 사이트인 척 API 콜을 요청할 수도 있다. - CSRF 공격 공격자가 다른 사이트에서 우리 사이트의 API 콜을 요청해 실행하는 공격이다.
API 콜을 요청할 수 있는 클라이언트 도메인이 누구인지 서버에서 통제하고 있지 않다면 CSRF가 가능한데, 이때 공격자가 클라이언트에 저장된 유저 인증정보를 서버에 보낼 수 있다면, 제대로 로그인한 것처럼 유저의 정보를 변경하거나 유저만 가능한 액션들을 수행할 수 있다. 예를 들어 CSRF에 취약한 은행 사이트가 있다면 로그인한 척 계좌 비밀번호를 바꾸거나 송금을 보낼 수 있는 것이다. - cors의 이유
3. 결론
1) 로그인 방식 선택 - jwt
로드밸런서를 쓰고 있고 서버도 두개이기 때문에 세션 쿠키 방식을 쓰게 된다면 쿠키를 발행한 서버와 발행하지 않은 서버에 대한 처리를 추가적으로 해줘야 하는 번거로움이 있어서 jwt를 선택하였다.
2) 브라우저 저장소 선택 - 로컬 스토리지
보안 관련 문제가 있기는 하지만 보안이 필요한 정보를 가지고 있는 프로젝트가 아니었기 때문에 개발편의상 로컬스토리지를 사용하였다.
3) 구현
그 외의 api는 호출시마다 accessToken의 만료여부를 파악해서 만료되었다면 error관련 액션으로 dispatch (redux - saga 이용)
4. 참고 자료들
http://www.opennaru.com/opennaru-blog/jwt-json-web-token/
https://velog.io/@_woogie/JWT-로그인방식-구현하기-feat.-session에서-jwt로
https://velog.io/@yaytomato/프론트에서-안전하게-로그인-처리하기
'web' 카테고리의 다른 글
React 18 (Suspense를 이용한 ssr 아키텍처) 를 읽고 (0) | 2021.06.20 |
---|---|
git commit message convention (0) | 2021.06.13 |
pc chrome 렌더링은 정상적으로 되는데, ios chrome에서 렌더링이 안될때 - (SyntaxError: Invalid regular expression: invalid group specifier name) (2) | 2021.06.12 |
브라우저 렌더링 과정 (0) | 2021.06.08 |
react - code splitting (1) | 2021.06.04 |