11. ๐ ํ๋ก ํธ์๋ ๋ณด์ ์ํ๊ณผ ๋ฐฉ์ด ์ ๋ต
๐ ๊ฐ์
ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๊ฐ ๋ฐ๋์ ์์์ผ ํ XSS, CSRF ๊ณต๊ฒฉ ๋์๋ฒ๊ณผ ์์ ํ ์ธ์ฆ ์์คํ ๊ตฌ์ถ ์ ๋ต์ ๋ง์คํฐํฉ๋๋ค.
๐ ์ด ๋ฉด์ ํญ๋ชฉ์ ๋ชฉํ
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 20๋ถ (ํต์ฌ ์์ฝ: 10๋ถ)
๐บ๏ธ ์ด ์ฑํฐ์ ํ๋ฆ
[๊ฐ๋
์ฌ์ ] โ [์ง๋ฌธ 1: XSS & CSRF ๋ฐฉ์ด] โ [์ง๋ฌธ 2: ํ ํฐ ๋ณด์ & SSR ์ธ์ฆ] โ [์ค์ ๋ณํ ์ง๋ฌธ]
๐ฏ ์ด ์ฑํฐ๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ ๋ฐ์ํ ์ ์๋ ์ฃผ์ ๋ณด์ ์ํ์ ์๋ฆฌ์ ๋ฐฉ์ด ๊ธฐ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
Content Security Policy(CSP)๋ฅผ ํ์ฉํ์ฌ ๋ณด์ ์์ค์ ๊ฐํํ๋ ๋ฒ์ ์ตํ๋๋ค.- ์ Access Token์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅํ๋ฉด ์ ๋๋์ง ๋ณด์์ ๊ด์ ์์ ๋ ผํฉ๋๋ค.
๐ ํต์ฌ ๊ฐ๋ ์ฌ์ (Concept Glossary)
1. XSS (Cross-Site Scripting)
๊ณต๊ฒฉ์๊ฐ ์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์ฝ์ ํ์ฌ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์์ ์คํ๋๊ฒ ๋ง๋๋ ๊ณต๊ฒฉ์ ๋๋ค. ์ฟ ํค ํ์ทจ, ์ธ์ ๊ฐ๋ก์ฑ๊ธฐ ๋ฑ์ด ๊ฐ๋ฅํด์ง๋ฉฐ ํ๋ก ํธ์๋ ๋ณด์์ ์ต๋ ๊ณต๊ณต์ ์ ์ ๋๋ค.
2. CSRF (Cross-Site Request Forgery)
์ฌ์ฉ์๊ฐ ์์ ์ ์์ง์ ๋ฌด๊ดํ๊ฒ ๊ณต๊ฒฉ์๊ฐ ์๋ํ ํ์(๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ, ์ก๊ธ ๋ฑ)๋ฅผ ํน์ ์น์ฌ์ดํธ์ ์์ฒญํ๊ฒ ๋ง๋๋ ๊ณต๊ฒฉ์ ๋๋ค. ์ฌ์ฉ์๊ฐ ์ด๋ฏธ ์ธ์ฆ๋ ์ธ์ ์ ๊ฐ์ง๊ณ ์๋ค๋ ์ ์ ์ ์ฉํฉ๋๋ค.
3. HttpOnly & Secure Cookie
- HttpOnly: ์๋ฐ์คํฌ๋ฆฝํธ(
document.cookie)๋ก ์ฟ ํค์ ์ ๊ทผํ๋ ๊ฒ์ ๋ง์ XSS๋ก๋ถํฐ ํ ํฐ์ ๋ณดํธํฉ๋๋ค. - Secure: ์ค์ง HTTPS ์ฐ๊ฒฐ์์๋ง ์ฟ ํค๊ฐ ์ ์ก๋๋๋ก ํ์ฌ ํต์ ๊ณผ์ ์ ์ ์ถ์ ๋ฐฉ์งํฉ๋๋ค.
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ๐ฃ ์์ฒ ( ์ ์
): "์ํธ ๋! '์์๋ค ๊ฒ์ํ' ๋๊ธ์ ๋๊ตฐ๊ฐ
<script>alert('ํดํน๋จ')</script>์ ์์ํ๊ฒ ๊น์๋จ์ด์! ๐ฑ ๋คํํ ์๋ฆผ๋ง ๋จ๋๋ฐ, ์ง์ง ํด์ปค๋ผ๋ฉด ์ด์ฉ์ฃ ?" - ๐ฆ ์ํธ ( ๋ฆฌ๋ ): "์์ฒ ๋, ๊ทธ๊ฑด ํด์ปค๊ฐ ๋ณด๋ธ '๊ฒฝ๊ณ ์ฅ'์
๋๋ค. ์ง๊ธ์
alert์ด์ง๋ง ๋ค์์ ์ ์ ์ ๋ก๊ทธ์ธ ์ ๋ณด๊ฐ ํด์ปค ์๋ฒ๋ก ์ ์ก๋๊ฒ ์ฃ . ํ๋ก ํธ์๋๋ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๋ด๋ '๊ธ๊ณ '์ ์ ๊ตฌ์์. ์ ๊ตฌ๊ฐ ๋ซ๋ฆฌ๋ฉด ๊ธ๊ณ ๋ ๋ฌด์๋ฏธํฉ๋๋ค."
Q1. XSS์ CSRF ๊ณต๊ฒฉ์ ๊ฒฐ์ ์ ์ธ ์ฐจ์ด์ ๊ณผ, ๊ฐ๊ฐ์ ํ๋ก ํธ์๋ ์ธก ๋ฐฉ์ด ์ ๋ต์ ์ค๋ช ํด ๋ณด์ธ์.
๐ฏ ์ถ์ ์๋
์น ๋ณด์์ 2๋ ์ฐ๋งฅ์ ์ ํํ ๊ตฌ๋ถํ๊ณ ์๋์ง ํ์ธํฉ๋๋ค. ๊ณต๊ฒฉ์ '์ฃผ์ฒด'์ '๋์'์ ์ดํดํด์ผ ์ฌ๋ฐ๋ฅธ ๋ฐฉ์ด ๋ก์ง์ ์งค ์ ์์ต๋๋ค.
๐ฃ ์์ฒ ์ด์ Naive ๊ตฌํ (Bad Case)
์์ฒ ์ด๋ ๊ฒ์ํ ๋ฐ์ดํฐ๋ฅผ dangerouslySetInnerHTML๋ก ์๋ฌด ๊ฒ์ฆ ์์ด ๋ ๋๋งํ๊ณ ์์ต๋๋ค.
// ๐ฃ ์์ฒ : "์๋ฒ์์ ์จ ๋ฐ์ดํฐ๋๊น ๋ฏฟ์ด๋ ๋๊ฒ ์ฃ ?"
function PostContent({ content }) {
// โ ๏ธ ์ํ: content์ <script> ํ๊ทธ๊ฐ ํฌํจ๋์ด ์๋ค๋ฉด ๊ทธ๋๋ก ์คํ๋จ (XSS)
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}๐ฆ ์ํธ์ ํฉํญ ์กฐ์ธ
"์์ฒ ๋, 'dangerously'๋ผ๋ ์ด๋ฆ์ด ๋ถ์ ์ด์ ๊ฐ ์์ด์. ์ฌ์ฉ์์ ์ ๋ ฅ์ ์ ๋ ๋ฏฟ์ง ๋ง์ธ์. ๊ทธ๋ฆฌ๊ณ CSRF๋ ์ฐ๋ฆฌ ์ฌ์ดํธ๊ฐ ์๋๋ผ '๋จ์ ์ฌ์ดํธ'์์ ์ฐ๋ฆฌ์๊ฒ ์ด์ ์๋ ๊ฑฐ๋ผ๋ ๊ฑธ ์์ง ๋ง์ธ์."
๐ฆ ์ํธ์ ์ํคํ ์ฒ ๊ฐ์ด๋ (Good Case)
์ํธ ๋ฆฌ๋๊ฐ ์ ์ํ๋ 2์ค, 3์ค ๋ณด์ ๋ ์ด์ด์ ๋๋ค.
// ๐ฆ ์ํธ: "๋ซ๋ฆด ์ ์๋ค๋ ๊ฐ์ ํ์ ์ค์ฒฉ๋ ๋ฐฉํจ๋ฅผ ์ธ์ฐ์ธ์."
// 1. XSS ๋ฐฉ์ด (Sanitization)
import DOMPurify from 'dompurify'; // โ
ํ์ฉ๋ ํ๊ทธ๋ง ๊ณจ๋ผ๋ด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ
function SafePostContent({ content }) {
const cleanContent = DOMPurify.sanitize(content);
return <div dangerouslySetInnerHTML={{ __html: cleanContent }} />;
}
// 2. CSRF ๋ฐฉ์ด
// - SameSite Cookie ์ค์ : ์ฟ ํค๊ฐ ์ค์ง '์ฐ๋ฆฌ ์ฌ์ดํธ'์์๋ง ์ ์ก๋๋๋ก ์ ํ
// - CSRF Token: ์๋ฒ์์ ๋ฐ๊ธํ ์ผํ์ฉ ํ ํฐ์ ํค๋์ ๋ด์ ์ ์ก
// - Custom Header: API ์์ฒญ ์ X-Requested-With ๊ฐ์ ์ปค์คํ
ํค๋ ๊ฐ์ (Cross-origin ์ฐจ๋จ)๐ ๋ ๋ฒจ๋ณ ๋ต๋ณ ๊ฐ์ด๋ (Self-Check)
- Level 1 (Junior): "XSS๋ ๊ฒ์ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ๋ฆฌ๋ ๊ฒ์ด๊ณ , CSRF๋ ๋จ์ ์ฌ์ดํธ์์ ๋ด ๊ณ์ ์ผ๋ก ์์ฒญ์ ๋ณด๋ด๋ ๊ฒ์ ๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์จ์ ๋ง์์ผ ํฉ๋๋ค."
- Level 2 (Senior): "XSS ๋ฐฉ์ด๋ฅผ ์ํ ์ด์ค์ผ์ดํ(Escape) ์ฒ๋ฆฌ์ DOMPurify ํ์ฉ, CSP ์ค์ ์ ์ค์์ฑ์ ์ค๋ช
ํฉ๋๋ค. CSRF ๋ฐฉ์ด๋ฅผ ์ํด์๋ ์ฟ ํค์
SameSite์์ฑ(Strict/Lax)์ด ์ด๋ป๊ฒ ์์ฒญ์ ์ ์ดํ๋์ง ์๋ฆฌ๋ฅผ ์ ์ํฉ๋๋ค." - Level 3 (Specialist): "ํ๋์ ์ธ SPA ํ๊ฒฝ์์ JWT๋ฅผ ํ์ฉํ ๋์ ๋ณด์ ํธ๋ ์ด๋์คํ๋ฅผ ๋
ผํฉ๋๋ค. XSS๋ '์คํฌ๋ฆฝํธ ์คํ ์ ์ง'๊ฐ ํต์ฌ์ด๊ณ , CSRF๋ '์์ฒญ์ ์ถ์ฒ ๊ฒ์ฆ'์ด ํต์ฌ์์ ์ํคํ
์ฒ ๊ด์ ์์ ๋ถ์ํฉ๋๋ค. ๋ํ
Referrer-Policy๋STS(Strict-Transport-Security)๊ฐ์ ๊ณ ๊ธ ๋ณด์ ํค๋ ํ์ฉ ๊ฒฝํ์ ๊ณต์ ํฉ๋๋ค."
Q2. ์ธ์ฆ ํ ํฐ(Access Token)์ ์ ์ฅํ ๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ฟ ํค ์ค ์ด๋ ๊ฒ์ด ๋ ์์ ํ๊ฐ์? ๊ทธ ์ด์ ์ ์ค์ต์ ์ธ ๋ณด์ ์ ๋ต์ ์ค๋ช ํด ๋ณด์ธ์.
๐ฏ ์ถ์ ์๋
๋ณด์๊ณผ ํธ์์ฑ ์ฌ์ด์ ํธ๋ ์ด๋์คํ๋ฅผ ์ดํดํ๊ณ ์๋์ง ํ์ธํฉ๋๋ค. ์ ๋ต์ ์์ง๋ง, ๊ฐ ์ ํ์ง์ ๋ฐ๋ฅธ '์ํ ๋ชจ๋ธ๋ง' ๋ฅ๋ ฅ์ ํ๊ฐํฉ๋๋ค.
๐ฃ ์์ฒ ์ด์ Naive ๊ตฌํ (Bad Case)
์์ฒ ์ด๋ ๊ตฌํ์ด ํธํ๋ค๋ ์ด์ ๋ก Access Token์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅํฉ๋๋ค.
// ๐ฃ ์์ฒ : "์๋ก๊ณ ์นจํด๋ ๋ก๊ทธ์ธ ์ ํ๋ฆฌ๊ฒ ํ๋ ค๋ฉด ๋ก์ปฌ ์คํ ๋ฆฌ์ง๊ฐ ์ ์ผ ํธํด์!"
localStorage.setItem('accessToken', token);
// โ ๏ธ ์น๋ช
์ ์ฝ์ : XSS ํ ๋ฐฉ์ด๋ฉด ํด์ปค๊ฐ ๋ชจ๋ ์ ์ ์ ํ ํฐ์ ๋ค ํธ์ด๊ฐ ์ ์์๐ฆ ์ํธ์ ํฉํญ ์กฐ์ธ
"์์ฒ ๋, ๋ก์ปฌ ์คํ ๋ฆฌ์ง๋ ์๋ฐ์คํฌ๋ฆฝํธ์๊ฒ '๋๋ฅผ ๋ง์๊ป ์ฝ์ด์ค'๋ผ๊ณ ๊ด๊ณ ํ๋ ๊ณณ์ด์์. ํด์ปค์๊ฒ ๋ ๋ ์นดํซ์ ๊น์์ฃผ๋ ์ ์ด์ฃ . ๋ณด์์ ์กฐ๊ธ ๋ถํธํ๋๋ผ๋ '์์ ํ ๊ธธ'๋ก ๊ฐ์ผ ํฉ๋๋ค."
๐ฆ ์ํธ์ ์ํคํ ์ฒ ๊ฐ์ด๋ (Good Case)
์ํธ ๋ฆฌ๋๊ฐ ์ ์ํ๋ 'ํ์ด๋ธ๋ฆฌ๋ ๋ณด์ ์ ๋ต'์ ๋๋ค.
// ๐ฆ ์ํธ: "์ค์ํ ์ด์ ๋ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋ง์ง ์ ์๋ ๊ณณ์ ๋์ธ์."
/*
1. Refresh Token: HttpOnly & Secure ์ฟ ํค์ ์ ์ฅ
- ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์ ๊ทผ ๋ถ๊ฐ (XSS ๋ฐฉ์ด)
- CSRF ๋ฐฉ์ด๋ฅผ ์ํด SameSite ์ค์ ํ์
2. Access Token:
- ๋ฐฉ๋ฒ A: ๋ฉ๋ชจ๋ฆฌ(React State)์ ์ ์ฅ (๊ฐ์ฅ ์์ ํ์ง๋ง ์๋ก๊ณ ์นจ ์ ๋ ์๊ฐ)
- ๋ฐฉ๋ฒ B: ์งง์ ์ ํจ๊ธฐ๊ฐ์ ๊ฐ์ง ํ ํฐ์ผ๋ก ๊ด๋ฆฌํ๊ณ ,
Silent Refresh ๋ฉ์ปค๋์ฆ์ ํตํด ์ฟ ํค์ Refresh Token์ผ๋ก ์ฌ๋ฐ๊ธ
*/๐ ๋ ๋ฒจ๋ณ ๋ต๋ณ ๊ฐ์ด๋ (Self-Check)
- Level 1 (Junior): "์ฟ ํค๊ฐ ๋ ์์ ํฉ๋๋ค. HttpOnly ์ค์ ์ ํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋ชป ์ฝ๊ธฐ ๋๋ฌธ์ ๋๋ค."
- Level 2 (Senior): "๋ก์ปฌ ์คํ ๋ฆฌ์ง๋ XSS์ ์ทจ์ฝํ๊ณ , ์ฟ ํค๋ CSRF์ ์ทจ์ฝํ๋ค๋ ์ ์ ๋น๊ต ์ค๋ช
ํฉ๋๋ค. ๋ฐ๋ผ์ ์ฟ ํค ์ฌ์ฉ ์
SameSite: Lax/Strict์ค์ ๊ณผCSRF Token๋ฐฉ์์ ๋ณํํด์ผ ํจ์ ๊ฐ์กฐํฉ๋๋ค." - Level 3 (Specialist): "'์ธ์ ํ์ด์ฌํน' ๋ฐฉ์ด๋ฅผ ์ํ ํฌ๊ด์ ์ธ ์ ๋ต์ ์ ์ํฉ๋๋ค. ํ ํฐ์ ์ ํด ์๊ฐ(Idle time) ๊ด๋ฆฌ, ์ค๋ณต ๋ก๊ทธ์ธ ๊ฐ์ง, ๊ทธ๋ฆฌ๊ณ ํ๋ก ํธ์๋ BFF(Backend For Frontend) ํจํด์ ํตํด ํด๋ผ์ด์ธํธ์ ํ ํฐ์ ์์ ๋ ธ์ถํ์ง ์๋ ๋ณด์ ์ํคํ ์ฒ๋ฅผ ์ค๋ช ํฉ๋๋ค."
๐ ์ค์ ๋ณํ ์ง๋ฌธ (Related Variations)
Q212. CSP(Content Security Policy)๋ ๋ฌด์์ด๋ฉฐ, ์ ์ค์ ํด์ผ ํ๋์?
- ๐ฏ ์ถ์ ์๋: ๋ธ๋ผ์ฐ์ ๋ ๋ฒจ์์ ๋ณด์ ์ ์ฑ ์ ๊ฐ์ ํ๋ '์ตํ์ ๋ฐฉ์ด์ '์ ๋ํด ์๋์ง ํ์ธํฉ๋๋ค.
- ๐ก ํต์ฌ ์๋ฆฌ & ๋ต๋ณ: CSP๋ HTTP ํค๋๋ฅผ ํตํด ๋ธ๋ผ์ฐ์ ๊ฐ ์์์ ๋ก๋ํ ์ ์๋ ์์ ํ ์ถ์ฒ(Origin)๋ฅผ ๋ช ์ํ๋ ๋ณด์ ๋ ์ด์ด์ ๋๋ค. ์๋ฅผ ๋ค์ด "์คํฌ๋ฆฝํธ๋ ์ค์ง ์ฐ๋ฆฌ ์๋ฒ์ Google Analytics์์๋ง ๋ฐ์์!"๋ผ๊ณ ์ ์ธํ๋ฉด, ๊ณต๊ฒฉ์๊ฐ ์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์ฝ์ ํด๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์คํ์ ๊ฑฐ๋ถํฉ๋๋ค. ์ธ๋ผ์ธ ์คํฌ๋ฆฝํธ ์คํ ๊ธ์ง, Eval ์ฌ์ฉ ๊ธ์ง ๋ฑ์ ํตํด XSS ์ํ์ ํ๊ธฐ์ ์ผ๋ก ๋ฎ์ถ ์ ์์ต๋๋ค.
Q225. HTTPS์ ๋์ ์๋ฆฌ์ ์ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ ์ด๋ฅผ ์ ํํ ์์์ผ ํ๋์?
- ๐ฏ ์ถ์ ์๋: ๋ฐ์ดํฐ ์ํธํ์ ์ธ์ฆ์ ์ฒด๊ณ์ ๋ํ ๊ธฐ๋ณธ ์์์ ํ์ธํฉ๋๋ค.
- ๐ก ํต์ฌ ์๋ฆฌ & ๋ต๋ณ: HTTPS๋ ๊ณต๊ฐํค์ ๋์นญํค ์ํธํ ๋ฐฉ์์ ํผํฉํ์ฌ ํด๋ผ์ด์ธํธ์ ์๋ฒ ์ฌ์ด์ ํต์ ์ ๋ณดํธํฉ๋๋ค. ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ ๋จ์ํ '์ฃผ์์ฐฝ์ ์๋ฌผ์ '๋ง ๋ณด๋ ๊ฒ์ด ์๋๋ผ,
Secure์ฟ ํค ์ค์ ์ด HTTPS ํ๊ฒฝ์์๋ง ์๋ํ๋ค๋ ์ , ๊ทธ๋ฆฌ๊ณ ์ค๊ฐ์ ๊ณต๊ฒฉ(MITM) ์ ๋ณด์ ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ๋ ๋ฉ์ปค๋์ฆ์ ์ดํดํ์ฌ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ ์ ์ก ์ ์์ ์ฑ์ ๋ณด์ฅํด์ผ ํฉ๋๋ค.
Q230. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์กด์ฑ ๋ณด์(Supply Chain Attack)์ ๋ฐฉ์ดํ๋ ๋ฐฉ๋ฒ์?
- ๐ฏ ์ถ์ ์๋: ๋ด๊ฐ ์ง ์ฝ๋๋ฟ๋ง ์๋๋ผ ๋จ์ด ๋ง๋ ์ฝ๋(
node_modules)์ ์ํ์ฑ์ ๊ด๋ฆฌํ๋์ง ํ์ธํฉ๋๋ค. - ๐ก ํต์ฌ ์๋ฆฌ & ๋ต๋ณ:
npm audit์ ์ฃผ๊ธฐ์ ์ผ๋ก ์คํํ์ฌ ์๋ ค์ง ์ทจ์ฝ์ ์ ์ฒดํฌํ๊ณ ,lockํ์ผ์ ํตํด ๋ชจ๋ ํ์์ด ๋์ผํ๊ณ ์์ ํ ๋ฒ์ ์ ํจํค์ง๋ฅผ ์ฌ์ฉํ๋๋ก ๊ฐ์ ํด์ผ ํฉ๋๋ค. ๋ํ ์ค์ ํ๋ก์ ํธ๋ผ๋ฉดSnyk๊ฐ์ ๋ณด์ ๋๊ตฌ๋ฅผ CI/CD์ ์ฐ๋ํ์ฌ ์ทจ์ฝ์ ์ด ํฌํจ๋ ์ฝ๋์ ๋ฐฐํฌ๋ฅผ ์๋ ์ฐจ๋จํ๋ ํ๊ฒฝ์ ๊ตฌ์ถํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๐ฃ ์์ฒ ์ด์ ๋ณต๊ธฐ ์ผ๊ธฐ
์ค๋ ๋ณด์์ ๋ฐฐ์ฐ๋ฉด์ ๊ทธ๋์ ์ผ๋ง๋ ์ํ์ฒ๋งํ๊ฒ ์ฝ๋ฉํ๋์ง ๊นจ๋ซ๊ณ ๋ฑ์ ์์๋์ด ๋ฌ๋ค. "๊ธฐ๋ฅ๋ง ์ ๋๋ฉด ๋์ง"๋ผ๊ณ ์๊ฐํ๋ฉฐ localStorage์ ๋ค ๋๋ ค ๋ฐ์๋ ๊ฑด ์ ๋ง ํด์ปค์๊ฒ ์ง ์ด์ ๋ฅผ ๋์ ธ์ค ๊ผด์ด์๋ค. ๋ณด์์ 100๋ฒ ์ํด๋ 1๋ฒ ๋ซ๋ฆฌ๋ฉด ๋์ด๋ผ๋ ์ํธ ๋์ ๋ง์์ ํ์ ๋ช
์ฌํด์ผ๊ฒ ๋ค.
๐ก "๊ฐ๋ฐ์์ ํธ์๋ ๊ณง ํด์ปค์ ๊ธฐํ๋ค. ๋ถํธํจ์ ์ ํํ ๋ ์ฌ์ฉ์๋ ์์ ํด์ง๋ค."
๋ด์ผ์ ๋๋์ด ๋๋ฏธ๋ฅผ ์ฅ์ํ๋ ๋ง์ง๋ง ์ฑํฐ, '์์ง๋์ด๋ง ๋ฆฌ๋์ญ & ์ฝ๋ ํ์ง'์ ๋ฐฐ์ด๋ค. ๋จ์ํ ์ฝ๋ฉํ๋ ๊ธฐ๊ณ๋ฅผ ๋์ด, ํจ๊ป ์ผํ๊ณ ์ถ์ ๋๋ฃ๋ก ๋จ๋ ๋ฒ์ ๊ณ ๋ฏผํด ๋ณด์! ๐ค๐