쿠키
사용자가 로그인하면, 사용자 식별자를 암호화 또는 평문으로 쿠키에 담는 방식. 요청이 오면 쿠키에 담긴 식별자를 보고 유저를 구분한다.
- 장점
- 유효한 쿠키인지만 확인하면 되기에 서버자원과 비용을 아낄 수 있다.
- 서버를 무상태(stateless)로 만들어줌.
- 암호화를 하면 brute force 대응 가능(특정 횟수 이상 인증 실패시 ip 잠금)
- 간단히 구현 가능
- 단점
- 쿠키가 탈취되면 위장 가능
세션
인증이 완료되면 사용자 식별자를 서버(DB 등)에 저장하고 그 저장한 곳에 접근하기 위한 해시 값을 세션 ID로 지정. 이후 세션 ID를 쿠키에 담아 보내주고, 사용자로부터 요청이 오면 세션id로 사용자 식별자를 가져온다.
- 장점
- 세션id가 노출되어도 유의미한 정보를 가지고 있지 않음.
- 같은 유저가 다른 곳에서 로그인할 시, 누가 로그인 되어있는지 저장하고 있기에, 하나를 막을 수 있음.
- 단점
- 쿠키가 탈취되면 위장 가능
- 요청이 많아지면 서버에 부하가 심해져, 세션 DB와 서버를 확장해야 한다.
- 세션 관리 시스템에 문제가 생기면 시스템 전체에 문제가 생긴다.
JWT
인증이 되면, JWT 토큰(access token)을 클라이언트로 보내줌. 클라이언트는 헤더에 JWT를 적용하여 서버로 요청을 보내면 서버는 JWT을 디코딩하여 유저를 식별함.
- 장점
- 토큰이 유효한지만 확인하면 되기에 서버자원과 비용을 아낄 수 있다.
- 서버를 무상태(stateless)로 만들어줌.
- 단점
- 탈취에 취약하다. 따라서 refresh token을 만들고, access token에 만료기간을 설정함.
- XSS 공격, CSRF 공격에 대비해야함.
- refresh token도 탈취될 수 있지만 서버가 방어할 수 있는 방법을 제공함.
- 탈취에 취약하다. 따라서 refresh token을 만들고, access token에 만료기간을 설정함.
쿠키/세션 다룰 때 주의점
- httponly을 통해 XSS 공격 막기
- secure 옵션을 통해 패킷 탈취에 대비
- 식별자는 암호화하여, brute force 막기.
- 특정 횟수 이상 인증 실패 시 ip 차단
- CSRF 에 대비하기 위해 게시글에 html 입력 불가능하도록 하기.(sanitize)
- 쿠키 탈취에 대비하기 위해 너무 동떨어진 위치에서 요청 시 차단
- 암호화 시에는 레인보우 테이블 공격 방어로 salt를 섞고 한번 더 암호화하는 기법(bcrypt 등) 사용
- 만료기간 설정 or 브라우저 닫을 시 만료
JWT 다룰 때 주의점
- refresh token 탈취 시에 대응하기 위해, 같은 refresh token 사용이 두 번 감지되면 그 refresh token 이후 발급 된 모든 refresh token을 폐기
- https://developer-ping9.tistory.com/239
- 다만 이 경우에도 access token만 계속 탈취하거나, 공격자가 먼저 reissue 했을 땐, 감지 할 수 없다.
- access token 만료 전에 reissue 시 탈취된 것으로 판단하여 access token을 폐기시킬 수 있음
- 이 경우에도 access token 만료 후 리이슈해서 접근하면 감지할 수 없음.
쿠키 vs 세션
장단점만 보면 쿠키가 서버 확장에도 대응이 돼서 쿠키가 더 좋아보인다. 그런데 왜 사람들은 세션이 좋다고 하는 것일까? 로그인 상태를 저장하기에 동시 로그인 시 하나를 막을 수 있다지만, 서비스에 따라서는 동시로그인을 허용해야하는 경우가 많다. 정확히 어떤 차이점이 있을까?
Session ID in cookies vs. Encrypted cookie
- 쿠키 암호화가 세션에 비해 단점인 것
- 복잡한 암호화 알고리즘 필요, secret key 관리 필요, 비중앙화됨(동시로그인 못막음)
- 신뢰할 수 있는 암호화 알고리즘을 사용해야함
- 크기가 커서 네트워크 비용 발생 (바이트 수준 차이라 크게 문제는 안될듯)
글을 읽었을 때 게임과 같이 동시로그인을 꼭 막아야하는 경우가 아니면, 쿠키 암호화가 성능상/구현상 더 좋은 거 같음. 암호화 알고리즘도 라이브러리화 된 신뢰성 있는 것이 많기에 글에서 본 단점도 상쇄된다. secret key 관리만 개발자가 주의하면 될 거 같음.
물리적 해킹일 땐 어떻게?
ex) PC방에서 A유저가 로그인 하고 자리를 떴는데, B가 와서 그대로 사용할 경우
- 쿠키 / 세션의 경우 : 만료기간 두기가 최선일 거 같음.
- JWT : refresh token 사용 + refresh token 탈취 대비책은 위에서 “주의점”에 적은 대로.
네이버 로그인 방식
NID_AUT
,NID_SES
사용- 링크에 나온대로 두 쿠키를 복사한 후 다른 브라우저에 넣어봤는데, 로그인이 되었다.
- 그런데 다른 페이지로 이동하려니 로그인이 막힘. 다른 쿠키도 차례대로 넣어봤는데 동작하지 않음
- 네이버에 접속하자마자 바로
JSESSIONID
란 쿠키가 생성됨. 이름이나 값이 단순 숫자인것으로 보아 세션은 사용하는거 같은데, 로그인 후 새로 생기는 것들은 암호화 되어있고 기존JSESSIONID
와는 독립되어보임. - 서비스 형태, 위에서 나온 현상을 봤을때 SSO을 네이버에서도 사용하는 것 같음. 그런데 SSO를 어떤 방식으로 인증하는 걸까?
- 찾기가 어려움..
- 다만 쿠키를 봤을때, JWT는 사용하지 않는 것으로 보임. 그리고 SSO는 큰 규모의 서비스를 대상으로 하는데, 세션을 사용하면 성능에 한계가 있어보임. 그럼 쿠키/세션/JWT 중에 있다면, 쿠키를 암호화하여 사용하는 것으로 보이는데 구체적인 내부 방식은 모르겠음.
- Redis를 사용하면 세션 성능 문제를 해결할 수 있지만, 그렇게까지 세션을 고집할 이유는 없어보임.