https://2junbeom.tistory.com/142
[트러블 슈팅] 로그인 방식과 보안에 대한 고찰 - 1 (세션 로그인 방식과 jwt 토큰 발급 방식)
실제로 운영할 서버를 만들면서, 보안에 대해서도 신경을 굉장히 많이 쓰게 되었다.XSS 공격과 CSRF 공격을 막기 위해 공부한 것들을 정리하겠다. 우선 세션 로그인 방식과 jwt 토큰 발급 방식에
2junbeom.tistory.com
지난 포스트에서 로그인 방식을 선정해보았다.
이제 선정한 jwt 토큰 기반 로그인 방식을 사용할 때 어떤 보안 조치를 해야하는지 살펴보도록 하겠다.
우선 XSS 공격이란 무엇일까?
XSS 공격
- Cross Site Scripting의 약자로 게시판이나 웹 메일 등에 자바 스크립트와 같은 스크립트 코드를 삽입해
전혀 다른 기능이 동작하게 하는 공격이다.
- 이런 방식으로 동작하며, 사용자가 글을 입력할 수 있는 게시판, 웹 메일 등에서 XSS 공격이 유효하다.
그럼 XSS 공격을 통해 어떤 피해가 발생할 수 있을까
- 사용자의 쿠키 및 민감한 정보 탈취
- 사용자의 자바스크립트에 접근해 쿠키 정보 및 여러 정보를 탈취한다.
- 이를 이용해 서버에, 쿠키에 담긴 인증 정보를 보내 여러 작업을 수행할 수 있다.
- 악성 코드 다운로드
- 악성 스크립트 안에 URL을 포함시켜, 악성 코드를 다운받는 사이트로 보낸다.
이제 해결방안을 살펴보도록 하자.
- 사용자의 쿠키 정보 탈취 대응 방안
- 사용자의 쿠키 정보 탈취에 대한 대응 방안은 바로 HttpOnly 옵션을 설정해두는 것이다.
- 해당 옵션은 자바스크립트를 통한 쿠키 접근을 막는 옵션이다.
- 악성 코드 다운로드 대응 방안
- 사용자가 입력하는 모든 텍스트에 정규식을 적용하여 필터링을 수행하면 된다.
- <>과 같은 특수문자의 입력을 제한하면 해결할 수 있다.
그러면 HttpOnly 옵션으로 쿠키를 설정하면 쿠키에 저장된 정보를 빼앗길 일이 없나요? 라고 생각할 수 있다.
하지만 중간자 공격이라는 변수가 존재한다.
중간자 공격
- 중간자 공격은 단순하게 네트워크 상 전송되는 데이터 패킷에서 쿠키 정보를 탈취하는 것이다.
- 네트워크 전송 간 암호화 되지 않은 Http 프로토콜을 사용한다면 쿠키 정보를 아주 간단하게 빼앗길 수 있다.
- 반대로 말하면 Https 프로토콜을 통해 암호화하여 데이터를 전송한다면 쿠키 탈취를 막을 수 있다는 얘기다.
- Https에서만 쿠키 전송을 허용한다는 "Secure" 옵션을 설정해주면 된다.
중간 정리
- 자 그러면 현재까지의 내용을 정리하면 "쿠키에 HttpOnly 옵션과 Secure 옵션을 설정하여
인증 정보를 모두 쿠키에 저장하면 되겠네요!" 라는 결론이 나온다. - 그러나 인증 정보를 모두 쿠키에 저장하는 방식을 사용한다면 CSRF 공격에 취약해질 수 있다 ㅠㅠ
CSRF 공격이 뭔데요??!
이제부터 알아보도록 하자
CSRF 공격
- 현재 쿠키에 모든 인증 정보가 저장된 상황이다.
- 넷플릭스 시청을 위해 로그인을 한다.
- 로그인을 할 때 모든 인증 정보가 쿠키에 저장된다.
- 다음에 넷플릭스에 요청을 보낼 때 쿠키에 설정된 인증 정보가 같이 자동으로 전송되기에, 별 다른 인증 절차가 필요하지 않아진다.
- 악성 스크립트가 심어진 evil.com에 접속했다.
- 여러 가지 유혹광고를 뿌리치지 못 하고 한 가지 광고를 클릭했다.
- 이런! 해당 광고엔 다음과 같이 넷플릭스에 아이디와 비밀번호 변경을 요청하는 post 요청이 숨어있었다.
- 당신의 넷플릭스 아이디와 비밀번호가 바뀌게 되었다 ㅠㅠ
대략 이러한 흐름을 지니고 있다.
자 이제 인증 정보를 쿠키에 저장하면 안 된다는 사실을 알았을 것이다.
그렇다면 해결 방법은 무엇일까?
세션 ID를 사용하는 경우엔 CSRF 토큰을 사용하면 된다.
하지만 우리는 JWT 토큰을 사용 중이다.
JWT 토큰 사용 시 XSS 공격과 CSRF 공격을 방어하는 법
- 액세스 토큰을 이용한다면 바로 인증 없이 모든 요청을 보낼 수 있다는 사실을 알고 있을 것이다.
- 그렇다면 액세스 토큰을 쿠키에 저장하지 않고 다른 저장소에 저장하면 된다.
- 그 위치는 바로 자바스크립트의 private 밸류이다.
- 나는 프론트에 대해서 잘 알지 못 하지만 나름대로 열심히 찾아보았다.
- 자바스크립트에서 private 밸류로 변수를 설정 해두면 외부에서 접근할 방법이 없다고 한다.
- 자바스트립트의 private 밸류는 메모리에 변수를 저장하는 방식으로 메모리에 변수 값을 저장하니 당연히
자바스크립트를 통한 접근이 불가능하고, 이는 XSS 공격을 막는 수단이 될 수 있다.
- 여기서 단점이 하나 발생한다. 액세스 토큰을 메모리에 저장한다면 보안상으로는 훌륭하지만,
사용자가 새로고침을 할 때마다 메모리의 값이 날라가기 때문에 다시 액세스 토큰을 재발급 받아야한다는 점이다.
리프레시 토큰을 쿠키에 설정해두고, 사용자의 액세스 토큰이 만료되거나, 새로고침을 했을 경우 자연스럽게 토큰을 재발급 받을 수 있도록
코드를 작성하는 불편함만 조금 감수한다면, 우리는 훌륭한 보안 매커니즘을 가져갈 수 있다.
그렇기에 액세스 토큰을 재발급 받을 수 있는 리프레시 토큰만 쿠키에 설정해두고 사용하는 것이다.
여기서 의문이 하나 더 생길 수 있다.
- 리프레시 토큰을 사용해서 액세스 토큰을 재발급 받는 CSRF 공격이 있다면 어떡하죠?
- 맞다. 그래서 리프레시 토큰 하나만을 사용해서 액세스 토큰을 재발급 받을 수 없도록 로직을 만들어야 한다.
- 또한 리프레시 토큰을 액세스 토큰처럼 사용하지 못 하도록 서버에서 리프레시 토큰 발급 과정에 액세스 토큰 발급 과정과 차별점을 두어야 한다.
글이 길어진다 결론을 내보자
결론
- 액세스 토큰은 메모리에 저장하여 외부 접근을 차단한다.
- 리프레시 토큰은 쿠키에 HttpOnly, Secure 옵션을 설정하여 저장한다.
- 새로고침하거나 만료 시간이 지나 액세스 토큰이 사라진다면, 사용자 모르게 리프레시 토큰을 사용해서 액세스 토큰을 재발급 받아 사용해라
- 리프레시 토큰 단 하나만을 이용해서 토큰을 재발급 받을 수 없게 만들어라
- 나의 경우엔 사용자의 아이디나 이메일 같은 개인정보와 리프레시 토큰을 매핑 시켜, 해당 정보가 일치한다면 토큰을 재발급 받을 수 있도록 해두었다.
- 리프레시 토큰 단 하나만을 이용해서 토큰을 재발급 받을 수 없게 만들어라
- 당연히 액세스 토큰과 리프레시 토큰은 발급 과정에 차이를 두어 리프레시 토큰 값을 이용해서 엔드 포인트에 접근할 수 없도록 해야한다.
이렇게 정리를 할 수가 있겠다.
여러 글을 찾아보는데, 로컬 스토리지에 액세스 토큰을 저장하라는 말이 너무나 많았다.
그러나 로컬 스토리지에 액세스 토큰을 저장하면 너무 쉽게 토큰을 탈취 당할 수 있으니, 별 다른 이유가 없다면
메모리에 액세스 토큰을 저장해서 사용하도록 하자
사용자 경험 개선을 위한 사용자 몰래 토큰 재발급하기 기능도 추가하는 것을 잊지 말고 ...!
'☃️❄️개발일지, 트러블슈팅❄️☃️' 카테고리의 다른 글
[개발일지] Auto Scaling Group 적용과 무중단 배포(Rolling Update) 및 CI/CD 파이프라인 설정 (0) | 2025.01.14 |
---|---|
[개발일지] webp 확장자를 통한 이미지 제공 최적화 작업 (0) | 2025.01.03 |
[트러블 슈팅] 로그인 방식과 보안에 대한 고찰 - 1 (세션 로그인 방식과 jwt 토큰 발급 방식) (1) | 2024.12.02 |
[트러블 슈팅] 협업 간 데이터베이스 ddl 충돌 문제 (1) | 2024.11.29 |
[개발일지] TAVE 공식 홈페이지 개발 1. (개발, 백엔드, 브랜칭 전략, 커밋 컨벤션, 로깅 규칙, PR 템플릿) (2) | 2024.10.07 |