| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- 스프링부트
- useState
- Redux
- 리액트
- 백엔드개발자
- 타입스크립트
- security
- 정보처리기사
- It
- JWT
- 수제비
- Node.js
- 백엔드
- TS
- 웹개발자
- frontend
- JS
- 큐넷
- Authentication
- spring boot
- VUE
- 프론트엔드
- React
- 정보처리기사 실기
- spring
- JavaScript
- TypeScript
- Front-End
- 자바스크립트
- spring boot security
- Today
- Total
솔적솔적
결국 그렇게 저장했는가, 그에 따른 보안은 안전한가(브라우저 저장소 결정2편) 본문
웹에서 '로그인 상태 유지' 또는 '자동 로그인' 기능을 구현할 때
어느 저장소에 무엇을 두느냐는 보안, 편의성 균형의 문제다.
1편에서 저장소 종류와 특성을 정리했다면
2편에서는 공격 벡터인 XXS/CSRF를 기준으로 실전 방어법과
설계 패턴을 이리저리 생각하고 구글링한 결과를 정리해볼 예정이다.
(*이건 그저 구현하며 저의 생각을 정리하는 내용이지 정답은 아닙니다.)
- Access Token, Refresh Token 같은 것은
가능한 클라이언트쪽에서 JS접근 불가한 HttpOnly 쿠키 + Secure + SameSite 설정으로 관리하는 것으로하는 것이 좋다생각한다.
- Access Token은 가능한 **메모리(짧은 수명)**에서 관리하고 필요 시 refresh cookie로 재발급한다.
- 비민감한 데이터, 대용량인 데이터를 저장해야할 경우는 IndexedDB가 적합하며
- 로컬스토리지는 편할 수 있지만 XXS에 취약하므로 토큰 저장으로는 사용하면 위험, 권장치않는다. 비민감 UI 상태 혹은 편의성 데이터만 사용.
위협 모델(무엇을 막아야 하나
-> xxs, csrf, 브라우저 취약점, 물리적 접근 or 공유 기기로 인한 남은 세션으로 계정 탈취 등
- XXS가 뭔데? Cross Site Scripting - 공격자가 스크립트를 주입해 브라우저 저장소인 로컬, 세션, 인덱스드디비의 데이터와 DOM에 접근하여 토큰 탈취, 조작한다.
- CSRF가 뭔데? Cross-site Request Forgery - 사용자의 인증 쿠키가 자동으로 전송되어 의도치 않은 요청이 서버에서 실행됨.
브라우저 취약점/확장 - 악성 확장이나 브라우저 취약점으로 저장소 훔침 가능
물리적 접근/ 공유 기기 - 공용 PC에서 남은 세션 등
지금 이 위협 모델들을 기준으로 설계해보면 어느 정도 보안은 철저하게 구축되리라 믿으며 시작.
- Access Token은 메모리, Refresh는 HttpOnly
=> 이 방식으로 한다면 js로는 refresh token에 접근이 불가하여 XSS로 부터 안전도가 크게 올라간다.
CSRF는 SameSite, CSRF 토큰 또는 doble-submit cookie로 방어
그리고 Refresh token도 탈취되면 위험하니 Refresh 시 새 refresh token 발행이전 토큰 무효화를 적용시켜야한다.
토큰과 세션관리할 때 되도록이면 토큰 수명은 너무 길지 않게 설정하고
로그아웃 시 서버에서 토큰 무효화, 클라이언트 저장소에서 초기화해줘야한다.
이것 말고도 보안 관련 ESLint 규칙, 정적 분석 도구를 도입하는 방법
- eslint-plugin-no-unsanitized (Mozilla) — innerHTML, insertAdjacentHTML 같은 직접 DOM 삽입을 금지하거나 허용된 sanitizer 사용을 강제. XSS 예방에 유용.
- eslint-plugin-xss — XSS 관련 사용 패턴(예: 위험한 문자열 조작)을 찾아주는 추가 규칙
- @typescript-eslint + eslint:recommended + eslint-plugin-react 등 기본 룰셋(타입스크립트/React 프로젝트용)
- 규칙 추가
금지: eval, new Function(), document.write, innerHTML
* 참고: ESLint 보안 플러그인은 정적 검사라서 완벽치 않고, 결과는 반드시 리뷰해야 함 npm공식 문서 참고
.eslintrc.js 예시
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended'
],
plugins: ['no-unsanitized','xss','security'],
rules: {
'no-unsanitized/method': 'error',
'no-unsanitized/property': 'error',
'security/detect-eval-with-expression': 'error',
'xss/no-mixed-html': 'warn'
}
};
운영 모니터링: Sentry 설정, 민감정보 스크럽
운영모니터링으로 Sentry로 수집하여 에러 알림을 통해 로깅 수집이 가능하다.
sentry에는 에러/예외 + 퍼포먼스 트레이싱 + 리치 컨텍스트 제공
beforeSend 훅을 사용해 이벤트가 전송되기 전에 민감정보 제거/마스킹.
import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';
Sentry.init({
dsn: process.env.SENTRY_DSN,
integrations: [new BrowserTracing()],
tracesSampleRate: 0.1,
environment: process.env.NODE_ENV,
release: process.env.SENTRY_RELEASE,
beforeSend(event, hint) {
// 요청 헤더의 인증 정보 제거
if (event.request?.headers) {
delete event.request.headers['authorization'];
delete event.request.headers['cookie'];
}
// event.user 객체에 민감 정보가 있다면 지우기
if (event.user) {
delete event.user.email;
delete event.user.ip_address;
}
// 추가: breadcrumbs/extra 에 들어간 민감 데이터 스크럽
if (event.breadcrumbs) {
event.breadcrumbs = event.breadcrumbs.map(b => {
if (b.data && b.data.requestBody) {
// 예시 마스킹
b.data.requestBody = '[REDACTED]';
}
return b;
});
}
return event;
}
});
- Alert rules: 신규 에러, 급증 에러 알림 설정(Slack/PagerDuty)
- 샘플링/레이트리밋: 비용관리 및 과다수집 방지
정리
- Refresh Token: HttpOnly + Secure + SameSite 설정
- Access Token: 메모리(짧은 수명)로 관리
- local/session storage: 토큰 절대 저장 금지
- IndexedDB: 비민감 대용량 데이터용
- CSRF 방어: SameSite + CSRF 토큰 적용
- 토큰 회전 및 서버 무효화(로그아웃) 구현
- ESLint 보안 플러그인 도입 + Husky + lint-staged 적용
- Sentry: beforeSend로 PII 제거, sourcemap 업로드, 알림 룰 설정
참고자료
- eslint-plugin-security (npm) — https://www.npmjs.com/package/eslint-plugin-security
- eslint-plugin-no-unsanitized (Mozilla GitHub) — https://github.com/mozilla/eslint-plugin-no-unsanitized
- Finding and Fixing DOM-based XSS with Static Analysis (Mozilla 블로그) —
https://blog.mozilla.org/attack-and-defense/2021/11/03/finding-and-fixing-dome-based-xss-with-static-analysis/ - ESLint — About — https://eslint.org/docs/latest/about/
- On Limitations of Modern Static Analysis Tools (연구) — https://par.nsf.gov/servlets/purl/10129360