Refresh Token 설계 가이드: JWT 자동 로그인과 세션 유지를 안전하게 만드는 기준
결론부터 말하면 Refresh Token은 오래 살아 있는 JWT 하나를 클라이언트에 저장하는 기능이 아닙니다. 자동 로그인을 제공하되 안전하게 운영하려면 Access Token은 짧게, Refresh Token은 서버의 세션 상태와 연결해 저장·회전·폐기·탐지해야 합니다. 로그아웃 후에도 토큰이 살아 있는지, 여러 기기 로그인은 어떻게 끊을지, 탈취가 의심될 때 어떤 범위로 무효화할지를 먼저 정책으로 정하고 그다음 구현해야 유지보수 비용이 줄어듭니다.

운영 기준 한 줄 요약: Access Token은 권한 확인용 짧은 증명서, Refresh Token은 서버에서 폐기 가능한 장기 세션 키로 다뤄야 합니다.
1. Refresh Token 설계가 중요한 이유
JWT 기반 로그인은 구현이 쉬워 보입니다. 로그인 성공 시 Access Token과 Refresh Token을 발급하고, Access Token이 만료되면 Refresh Token으로 새 토큰을 받으면 됩니다. 문제는 출시 이후에 발생합니다. 사용자가 로그아웃했는데 탈취된 Refresh Token으로 다시 로그인 상태가 살아나거나, 한 사용자가 여러 기기에서 로그인했을 때 특정 기기만 끊지 못하거나, 관리자 권한이 변경됐는데 기존 토큰이 계속 권한을 유지하는 상황이 생깁니다.
OAuth 2.0 Security Best Current Practice인 RFC 9700은 public client의 Refresh Token에 대해 sender-constrained 방식 또는 Refresh Token rotation을 사용해 replay를 탐지하도록 요구합니다. 브라우저 SPA나 모바일 앱처럼 클라이언트 비밀을 안전하게 숨기기 어려운 환경에서는 이 원칙을 자체 JWT 로그인에도 적용하는 것이 안전합니다. ([rfc-editor.org](https://www.rfc-editor.org/rfc/rfc9700))
즉 Refresh Token 설계는 개발자가 알아서 정하는 세부 구현이 아니라, 서비스 운영 정책입니다. B2B SaaS, 앱 서비스, 관리자 시스템, 정부지원사업 MVP 모두 로그인 화면은 비슷해 보여도 세션 수명, 저장 위치, 폐기 범위, 로그 추적 요건은 달라야 합니다.
2. Access Token과 Refresh Token의 역할을 분리해야 한다
| 항목 | Access Token | Refresh Token |
|---|---|---|
| 주 용도 | API 요청 시 권한 확인 | 새 Access Token 발급 |
| 수명 | 짧게 운영 | 상대적으로 길지만 idle·absolute 만료 필요 |
| 서버 저장 | JWT라면 보통 저장하지 않음 | 해시 또는 세션 레코드로 저장 권장 |
| 탈취 시 영향 | 만료 전까지 API 접근 가능 | 새 Access Token을 계속 만들 수 있어 더 위험 |
| 폐기 방식 | 짧은 만료, denylist, 세션 버전 검사 등 | DB 세션 폐기, token family 폐기, 회전 재사용 탐지 |
Access Token은 리소스 서버가 빠르게 검증할 수 있도록 설계합니다. JWT Access Token을 쓴다면 iss, aud, exp, 서명 알고리즘, 키 식별자 등을 검증해야 하며, RFC 9068은 JWT Access Token 검증 시 발급자, 대상, 서명, 만료, 토큰 타입 등을 확인해야 한다고 설명합니다. ([ietf.org](https://www.ietf.org/rfc/rfc9068.html))
반면 Refresh Token은 매 요청마다 API 권한 확인에 쓰면 안 됩니다. Refresh Token은 새 Access Token을 받기 위한 고가치 자격 증명입니다. 따라서 원문 토큰을 DB에 저장하기보다 충분히 긴 난수 토큰을 발급하고, 서버에는 해시만 저장하는 편이 안전합니다. DB가 유출되더라도 해시만으로는 바로 Refresh Token을 사용할 수 없기 때문입니다.
3. 만료 시간은 하나가 아니라 세 가지로 나눠야 한다
토큰 만료 시간을 정할 때 흔한 실수는 Refresh Token 만료만 30일로 잡고 끝내는 것입니다. 실제 운영에서는 최소 세 가지 시간이 필요합니다.
- Access Token 만료: 탈취된 Access Token이 API를 호출할 수 있는 최대 시간입니다.
- Refresh Token idle expiry: 일정 기간 사용하지 않은 세션을 닫는 시간입니다.
- Refresh Token absolute expiry: 계속 사용 중이어도 반드시 재로그인을 요구하는 최대 세션 수명입니다.
OWASP Session Management Cheat Sheet는 모든 세션에 비활성 타임아웃과 절대 타임아웃이 필요하며, 세션 만료는 서버 측에서 강제되어야 한다고 설명합니다. NIST SP 800-63B도 세션 타임아웃은 전체 타임아웃과 비활성 타임아웃으로 나누고, 서비스 특성·기기·위험도에 따라 문서화해야 한다고 봅니다. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html))
| 서비스 유형 | Access Token 예시 | Refresh Token 정책 예시 | 주의점 |
|---|---|---|---|
| 일반 SaaS 웹 | 10~15분부터 검토 | idle 7~30일, absolute 30~90일 등 정책화 | 자동 로그인 선택 여부에 따라 쿠키 Max-Age 분리 |
| 관리자·백오피스 | 5~10분부터 검토 | idle 30~60분, absolute 업무일 단위 검토 | MFA, IP 제한, 권한 변경 시 재인증 권장 |
| 모바일 앱 | 10~30분부터 검토 | 보안 저장소와 기기 식별을 전제로 장기 세션 검토 | 결제·개인정보 수정은 별도 재인증 |
| B2B API 연동 | 짧은 Access Token 또는 OAuth provider 정책 | Refresh Token이 필요 없는 client credentials도 검토 | scope, aud, client별 폐기 정책이 중요 |
위 숫자는 고정된 정답이 아니라 정책 수립을 위한 출발점입니다. 개인정보, 결제, 의료·금융 유사 데이터, 기업 관리자 기능이 있다면 더 보수적으로 잡아야 합니다. 반대로 콘텐츠 소비형 앱은 사용자 경험을 위해 긴 세션을 허용할 수 있지만, 그 경우에도 재사용 탐지와 기기별 폐기를 함께 설계해야 합니다.
4. Refresh Token 저장 위치: 웹, SPA, 모바일은 다르게 봐야 한다

웹 서비스: HttpOnly Cookie가 기본 후보
브라우저 기반 서비스에서는 Refresh Token을 JavaScript가 읽을 수 있는 저장소에 두지 않는 편이 안전합니다. OWASP HTML5 Security Cheat Sheet는 localStorage에 민감 정보나 세션 식별자를 저장하지 말라고 권고하며, localStorage는 JavaScript에서 접근 가능하므로 XSS에 취약합니다. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html))
따라서 웹에서는 Refresh Token을 HttpOnly, Secure, SameSite가 설정된 쿠키에 저장하는 방식을 우선 검토합니다. OWASP와 MDN은 세션 쿠키에 Secure, HttpOnly, SameSite를 명시하고 Domain과 Path를 최소화할 것을 권고합니다. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html))
| 저장 위치 | 장점 | 주의점 |
|---|---|---|
| HttpOnly Secure Cookie | JavaScript가 토큰을 직접 읽기 어려움 | 쿠키 자동 전송 때문에 CSRF 방어 필요 |
| Memory | 새로고침 시 사라져 탈취 지속성이 낮음 | 새로고침·탭 간 공유 UX 구현 필요 |
| localStorage | 구현이 쉬움 | XSS 한 번으로 장기 토큰 탈취 가능, Refresh Token 저장 비권장 |
| sessionStorage | 탭 단위로 제한 가능 | JavaScript 접근 가능하므로 고가치 토큰 저장에는 부적합 |
쿠키를 쓰면 CSRF를 같이 설계해야 한다
HttpOnly Cookie는 XSS로부터 토큰 값을 읽히는 위험을 줄이지만, 브라우저가 쿠키를 자동으로 보내기 때문에 CSRF를 별도로 막아야 합니다. SameSite만으로 모든 상황을 해결했다고 보지 말고, 상태 변경 요청에는 CSRF 토큰, Origin 검증, 커스텀 헤더, 엄격한 CORS 정책을 함께 적용하는 편이 안전합니다. OWASP CSRF Cheat Sheet도 SameSite를 방어 심화 계층으로 보고 다른 CSRF 방어와 조합할 것을 설명합니다. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html?utm_source=openai))
모바일 앱: Keychain·Keystore 계열을 검토
모바일 앱에서는 iOS Keychain, Android Keystore 기반 보안 저장소를 우선 검토합니다. Apple은 Keychain Services를 사용자 비밀값을 안전하게 보관하는 메커니즘으로 제공하고, Android Keystore는 키를 기기에서 추출하기 어렵게 보관하고 사용 조건을 제한할 수 있게 합니다. ([developer.apple.com](https://developer.apple.com/documentation/security/keychain-services?changes=_1&utm_source=openai))
React Native, Flutter, 네이티브 앱 모두 원칙은 같습니다. Refresh Token은 플랫폼 보안 저장소에 보관하고, Access Token은 가능하면 메모리에 두며, 앱 재시작 시 Refresh Token으로 새 Access Token을 발급받습니다. 단 루팅·탈옥·악성 앱·디버그 빌드 위험까지 완전히 제거하는 저장소는 없으므로, 서버 측 세션 폐기와 재사용 탐지가 반드시 필요합니다.
5. 안전한 갱신 방식: Refresh Token rotation이 기본 구조다

안전한 Refresh Token 설계의 핵심은 회전입니다. 클라이언트가 Refresh Token을 사용해 새 Access Token을 받으면 서버는 새 Refresh Token도 함께 발급하고, 이전 Refresh Token은 더 이상 사용할 수 없게 만듭니다. RFC 9700은 rotation 방식에서 이전 Refresh Token을 무효화하되 토큰 간 관계를 보존해 재사용을 탐지한다고 설명합니다. ([rfc-editor.org](https://www.rfc-editor.org/rfc/rfc9700))
- 사용자가 로그인하면 서버는 Access Token과 Refresh Token을 발급합니다.
- 서버는 Refresh Token 원문이 아니라 해시, 세션 ID, token family ID, 만료 시간, 기기 정보를 저장합니다.
- Access Token이 만료되면 클라이언트는 Refresh Token을 refresh endpoint로 보냅니다.
- 서버는 세션 상태, 해시 일치 여부, 만료 여부, 폐기 여부를 확인합니다.
- 정상이라면 이전 Refresh Token을 사용 처리하거나 폐기하고, 새 Refresh Token 해시로 교체합니다.
- 이미 사용된 Refresh Token이 다시 들어오면 재사용으로 판단하고 해당 token family 또는 기기 세션을 폐기합니다.
이 과정은 반드시 원자적으로 처리해야 합니다. 동시에 여러 탭에서 refresh 요청이 나가면 정상 사용자가 재사용 탐지에 걸릴 수 있습니다. 프론트엔드에서는 refresh 요청을 한 번만 보내는 single-flight 처리를 하고, 백엔드에서는 짧은 재시도 허용 구간이나 row lock을 설계해 네트워크 재전송과 실제 탈취를 구분할 수 있어야 합니다.
6. DB 세션 테이블은 Refresh Token 설계의 중심이다
JWT를 쓰면 서버가 상태를 전혀 갖지 않아도 된다고 오해하기 쉽습니다. 하지만 로그아웃 무효화, 기기별 세션 관리, 전체 기기 로그아웃, 탈취 탐지, 감사 로그가 필요하다면 Refresh Token은 서버 상태와 연결되어야 합니다. 실무에서는 다음과 같은 세션 테이블을 둡니다.
| 필드 | 용도 |
|---|---|
| id | 세션 또는 기기 세션 식별자 |
| user_id | 사용자 연결 |
| client_type | web, mobile, admin, partner 등 채널 구분 |
| device_id / device_name | 기기별 세션 관리와 사용자 노출용 |
| refresh_token_hash | 현재 유효한 Refresh Token 해시 |
| family_id | 회전된 토큰 묶음 추적 |
| issued_at / last_used_at | 발급·마지막 사용 시각 |
| idle_expires_at / absolute_expires_at | 비활성·절대 만료 시각 |
| revoked_at / revoke_reason | 로그아웃, 관리자 차단, 재사용 탐지 등 폐기 사유 |
| ip_address / user_agent | 보안 이벤트 분석용. 개인정보 보관 목적과 기간 필요 |
민감한 서비스라면 별도 session_events 테이블도 둡니다. 로그인 성공, refresh 성공, refresh 실패, 재사용 탐지, 로그아웃, 전체 기기 로그아웃, 비밀번호 변경, 관리자 강제 종료를 이벤트로 남기면 보안 점검과 고객사 대응이 쉬워집니다. 이 로그를 실제 장애·보안 탐지에 쓰려면 OpenTelemetry 관측성 가이드에서 다룬 것처럼 API 오류율, 401·403 증가, refresh 실패율, 특정 IP 반복 실패를 모니터링 지표로 연결해야 합니다.
7. 로그아웃은 쿠키 삭제가 아니라 서버 세션 폐기다
클라이언트에서 쿠키나 저장소를 삭제하는 것만으로는 로그아웃이 끝나지 않습니다. 이미 탈취된 Refresh Token이 있다면 서버 DB에서 해당 세션을 폐기하지 않는 한 다시 Access Token을 받을 수 있습니다. OAuth 2.0 Token Revocation RFC 7009도 revocation 요청이 실제 토큰을 무효화하고, 정책에 따라 관련 토큰과 authorization grant까지 무효화할 수 있다고 설명합니다. ([datatracker.ietf.org](https://datatracker.ietf.org/doc/html/rfc7009))
| 상황 | 서버 동작 | 클라이언트 동작 |
|---|---|---|
| 현재 기기 로그아웃 | 해당 session_id 또는 token family 폐기 | Refresh Token 쿠키·보안 저장소 삭제 |
| 전체 기기 로그아웃 | user_id 기준 모든 활성 세션 폐기 | 각 기기는 다음 refresh 시 로그인 화면 이동 |
| 비밀번호 변경 | 기존 Refresh Token 전부 폐기 또는 재인증 요구 | 사용자에게 재로그인 안내 |
| 권한 변경 | Refresh Token 폐기, Access Token 짧은 만료 또는 세션 버전 검사 | 관리자 화면 권한 재조회 |
| 탈취 의심 | token family 폐기, 보안 이벤트 기록, 필요 시 계정 잠금 | 재로그인 및 알림 |
주의할 점은 self-contained JWT Access Token은 만료 전까지 계속 유효할 수 있다는 점입니다. 그래서 Access Token을 짧게 가져가야 합니다. 즉시 차단이 필요한 관리자 기능이라면 Access Token에도 session_version, token_valid_after, denylist, introspection, opaque token 같은 서버 조회 구조를 추가해야 합니다.
8. 앱·웹·관리자별 정책을 다르게 가져가야 한다
한 서비스 안에서도 고객용 웹, 모바일 앱, 관리자 페이지, 운영자용 내부 도구의 세션 정책은 달라야 합니다. 관리자 페이지가 고객용 앱과 같은 30일 자동 로그인을 공유한다면, 보안 점검에서 지적될 가능성이 높고 실제 사고 영향도 큽니다.
- 고객용 웹: 자동 로그인 선택 시에만 persistent cookie를 쓰고, 선택하지 않으면 브라우저 세션 쿠키로 운영합니다.
- 모바일 앱: 기기 분실과 재설치, OS 보안 저장소, 생체 인증 재확인을 함께 고려합니다.
- 관리자 페이지: 짧은 idle timeout, MFA, 권한 변경 시 강제 재인증, IP 제한 또는 VPN을 검토합니다.
- B2B 고객사 테넌트: 고객사별 세션 정책을 다르게 적용할 수 있는 설정값이 필요할 수 있습니다.
특히 SaaS나 BizMit 같은 업무 운영 시스템에서는 관리자 대시보드, 자동화 작업, 외부 API 연동이 함께 존재합니다. 사용자 세션과 서버 간 API 인증을 섞으면 나중에 폐기 범위가 꼬입니다. 사람 로그인 세션, 관리자 세션, 서버 간 토큰, 외부 연동 토큰은 테이블과 정책을 분리하는 편이 유지보수에 유리합니다.
9. Refresh Token 설계에서 자주 나오는 위험한 구현
- Refresh Token을 localStorage에 저장: 구현은 쉽지만 XSS에 취약합니다.
- Refresh Token을 DB에 평문 저장: DB 유출 시 즉시 세션 탈취로 이어질 수 있습니다.
- 로그아웃 시 클라이언트 저장소만 삭제: 서버 세션이 살아 있으면 탈취 토큰은 계속 유효할 수 있습니다.
- 회전 없이 긴 Refresh Token 하나만 사용: 탈취 후 탐지가 어렵고 장기간 재사용될 수 있습니다.
- 모든 채널에 같은 만료 시간 적용: 고객용 앱과 관리자 시스템의 위험도가 다른데도 같은 정책을 쓰게 됩니다.
- 토큰을 URL query로 전달: 브라우저 히스토리, 로그, Referer로 노출될 수 있습니다.
- 토큰 값을 애플리케이션 로그에 남김: 장애 대응 과정에서 로그 시스템으로 토큰이 확산될 수 있습니다.
- JWT payload에 개인정보를 과도하게 넣음: JWT는 서명되어도 쉽게 디코딩되므로 최소 claim만 넣어야 합니다. Auth0도 토큰 payload에 민감 데이터를 넣지 말고 만료 전략을 두라고 안내합니다. ([auth0.com](https://auth0.com/docs/secure/tokens/token-best-practices))
10. 외주 개발 인수인계 시 확인할 Refresh Token 체크리스트

외주 개발 후 유지보수를 맡거나 내부 팀이 인수인계를 받는다면 로그인 성공 화면만 확인하면 안 됩니다. 인증 구조는 출시 후 고치기 어렵고, 고치더라도 기존 사용자 세션을 마이그레이션해야 하기 때문입니다. 기본적인 서버·DB·배포 인수인계는 외주개발 인수인계 체크리스트와 함께 확인하고, 인증 파트는 아래 항목을 별도로 점검하는 것이 좋습니다.
- Access Token과 Refresh Token 만료 시간이 환경변수 또는 설정 파일로 분리되어 있는가?
- Refresh Token 원문이 DB에 저장되지 않고 해시로 저장되는가?
- Refresh Token rotation이 적용되어 이전 토큰 재사용을 탐지하는가?
- 동시 refresh 요청에 대한 race condition 대응이 있는가?
- 현재 기기 로그아웃과 전체 기기 로그아웃 API가 구분되어 있는가?
- 비밀번호 변경, 회원 탈퇴, 관리자 권한 변경 시 Refresh Token이 폐기되는가?
- 관리자 계정은 고객 계정보다 짧은 세션 정책과 MFA 정책을 갖는가?
- 웹 쿠키에 Secure, HttpOnly, SameSite, Path, Domain이 명시되어 있는가?
- 쿠키 기반 인증에서 CSRF 토큰, Origin 검증, CORS allowlist가 적용되어 있는가?
- 모바일 앱의 Refresh Token이 Keychain·Keystore 기반 저장소에 들어가는가?
- 토큰이 URL, 에러 메시지, 서버 로그, 분석 도구에 남지 않도록 마스킹하는가?
- refresh 실패율, 재사용 탐지, 특정 IP 반복 실패를 모니터링하는가?
- 토큰 서명 키 교체 절차와 JWKS 또는 secret rotation 문서가 있는가?
- 스테이징과 운영의 JWT secret, cookie domain, CORS 설정이 분리되어 있는가?
- 인증 모듈 테스트 케이스에 만료, 로그아웃, 폐기, 재사용 탐지가 포함되어 있는가?
계약 단계라면 인증·보안 요구사항을 개발 범위에 명시해야 합니다. 단순히 로그인 구현이라고 쓰면 회전, 재사용 탐지, 전체 기기 로그아웃, 관리자 세션 정책이 누락되기 쉽습니다. 범위와 검수 조건을 정리할 때는 외주개발 계약서 필수 조항 체크리스트처럼 기능 목록뿐 아니라 검수 가능한 보안 조건까지 문서화하는 편이 안전합니다.
11. AgentMit이 보는 구현 우선순위
초기 MVP에서는 모든 보안 기능을 한 번에 넣기 어렵습니다. 다만 나중에 구조를 갈아엎지 않으려면 최소한 세션 테이블, Refresh Token 해시 저장, 로그아웃 서버 폐기, 만료 시간 설정 분리, 쿠키 보안 속성은 처음부터 넣는 것이 좋습니다. 이후 B2B 고객사 보안 요구나 앱 심사, 관리자 기능 확장 단계에서 rotation, 재사용 탐지, 전체 기기 로그아웃, 감사 로그, MFA를 확장하면 됩니다.
AgentMit은 Laravel·Node 기반 SaaS, 관리자 대시보드, 자동화 시스템, 정부지원사업 MVP를 설계할 때 Refresh Token을 단순 로그인 부가기능으로 보지 않습니다. BizMit 같은 업무 시스템에서는 사용자 세션, 관리자 세션, 자동화 API 토큰, 외부 연동 토큰이 함께 쓰이므로 처음부터 토큰 종류와 폐기 범위를 나누는 것이 운영 안정성에 직접 연결됩니다.
FAQ
Q1. Refresh Token은 꼭 JWT로 만들어야 하나요?
아닙니다. 실무에서는 예측 불가능한 opaque random token을 발급하고 서버 DB에는 해시만 저장하는 방식이 관리하기 쉽습니다. JWT Refresh Token을 쓰더라도 로그아웃, 회전, 탈취 탐지, 기기별 세션 관리를 하려면 결국 서버 측 세션 상태가 필요합니다.
Q2. Access Token과 Refresh Token 만료 시간은 몇 분, 며칠로 잡아야 하나요?
정답은 서비스 위험도와 UX에 따라 달라집니다. 일반 SaaS는 Access Token을 짧게, Refresh Token은 idle expiry와 absolute expiry를 함께 둡니다. 관리자·개인정보·결제 기능은 더 짧게 잡고, 모바일 앱은 보안 저장소와 재인증 정책을 전제로 더 긴 세션을 검토할 수 있습니다.
Q3. 웹에서 Refresh Token은 localStorage에 저장해도 되나요?
권장하지 않습니다. localStorage는 JavaScript에서 접근 가능하므로 XSS 한 번으로 토큰이 유출될 수 있습니다. 웹에서는 Refresh Token을 HttpOnly, Secure, SameSite가 설정된 쿠키에 두고, CSRF 방어와 CORS 제한을 함께 설계하는 편이 안전합니다.
Q4. 로그아웃하면 JWT Access Token도 즉시 무효화되나요?
기본적인 self-contained JWT는 서명 후 만료 전까지 유효합니다. 로그아웃 시 Refresh Token을 폐기하면 새 Access Token 발급은 막을 수 있지만, 이미 발급된 Access Token은 짧은 만료 시간으로 위험을 줄입니다. 즉시 차단이 필요하면 denylist, 세션 버전 검사, introspection, opaque token 같은 서버 조회 구조가 필요합니다.
Q5. Refresh Token 탈취를 어떻게 탐지하나요?
Refresh Token rotation을 적용하고, 이미 사용된 토큰이 다시 제출되면 재사용으로 판단합니다. 이때 해당 token family나 기기 세션을 폐기하고 사용자에게 재로그인을 요구하며, IP·기기·시간 정보를 보안 이벤트로 기록해야 합니다.
참고 기준
- RFC 9700: Best Current Practice for OAuth 2.0 Security - Refresh Token rotation, sender-constrained token, replay detection 기준
- RFC 7009: OAuth 2.0 Token Revocation - 로그아웃과 토큰 폐기 정책
- RFC 9068: JWT Profile for OAuth 2.0 Access Tokens - JWT Access Token 검증 기준
- OWASP Session Management Cheat Sheet - 쿠키 보안 속성, idle·absolute timeout
- OWASP HTML5 Security Cheat Sheet - localStorage와 세션 식별자 저장 위험
- OWASP CSRF Prevention Cheat Sheet - 쿠키 인증의 CSRF 방어
- MDN Secure Cookie Configuration - Secure, HttpOnly, SameSite, Domain, Path 설정
- NIST SP 800-63B - 세션 타임아웃과 재인증 기준

