[2025-08-11] CSRF&CORS Bypass
๐ฆฅ ๋ณธ๋ฌธ
CSRF Token
๋์ ํ๋ฆ
- ๊ฐ์ ์ค๋ฆฌ์ง์์๋ง ์ ๊ทผ ๊ฐ๋ฅํ ํํ๋ก ํน์ Token์ ์ธ์ ์ ์ ์ฅ
- ์๋ฒ๊ฐ HTML form ํ๊ทธ์
hidden
์์ฑ์ด๋ ๋ฉํ ํ๊ทธ๋ก ์ ๋ฌ - ์์ฒญ ์ ๋ค์ด์จ ํ ํฐ๊ณผ ์ธ์ ์ ํ ํฐ์ ๋น๊ต
์์
<?php
if (!isset($_SESSION["csrftoken"])) {
$csrftoken = bin2hex(random_bytes(32));
$_SESSION["csrftoken"] = $csrftoken;
} else {
$csrftoken = $_SESSION["csrftoken"];
}
$method = $_SERVER["HTTP_METHOD"];
if ($method !== "GET" && $method !== "HEAD") {
if (!isset($_POST["csrftoken"]) ||
!hash_equals($csrftoken, $_POST["csrftoken"]) {
header("HTTP/1.1 403 Forbidden");
die("CSRF detected");
}
echo "Input value: ";
echo htmlentities($_POST["query"], ENT_QUOTES|ENT_HTML5, 'utf-8');
}
?>
<form action="" method="POST">
<input name="csrftoken" type="hidden" value="<?=htmlentities($csrftoken, ENT_QUOTES|ENT_HTML5, 'utf-8'); ?>">
<input name="query" type="text" />
<input type="submit" />
</form>
์ฅ์
- ์ฌ์ฉ์์ ์ถ๊ฐ์ ์ธ ์ํธ์์ฉ ๋ถํ์ : CAPTCHA, OTP, ์ด๋ฉ์ผ ํ์ธ ๋ฑ๊ณผ ๊ฐ์ ๋ณด์ ๋์ฑ ๊ฐ์ ๊ฒฝ์ฐ์๋ ์ถ๊ฐ ์ธ์ฆ, ์ ๋ ฅ, ํด๋ฆญ ๋ฑ์ด ํ์ํ์ง๋ง CSRF Token์ ์๋์ผ๋ก ํ ํฐ ์ ์ก
- ์์กฐ ์์ฒญ ์ฐจ๋จ : ๊ณต๊ฒฉ์๋ ํ ํฐ๊ฐ์ ์ ์ ์์ผ๋ฏ๋ก ์์กฐ ๋ถ๊ฐ
- ๋ธ๋ผ์ฐ์ ์์กด๋ ๋ฎ์ : ํ ํฐ ์์ฑ ๋ฐ ๊ฒ์ฆ ๋ก์ง์ ์๋ฒ๊ฐ ์ ๋ดํ๋ฏ๋ก, ๋ธ๋ผ์ฐ์ /ํด๋ผ์ด์ธํธ ํ๊ฒฝ ๋ณํ์ ์๊ด์์ด ๋์. SameSite ์ฟ ํค ์ ์ฑ ๊ฐ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฅ๊ณผ ๋ฌด๊ดํ๊ฒ ์๋
์ฃผ์ ์ฌํญ
- ์งง์ CSRF Token : Brute-force attack์ผ๋ก ํ๋ํ ์ ์๋๋ก ๊ธธ์ด์ผ ํจ
- ์์ธก ๊ฐ๋ฅํ CSRF Token : PRNG ๊ฐ์ ์์ฌ ๋์ ์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์์ธก ๊ฐ๋ฅ. CSPRNG ๊ฐ์ ๋์ ์์ฑ๊ธฐ ์ฌ์ฉ
- CSRF Token ์ ์ถ : CSRF Token์ด URL ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ง๋ ๊ฒฝ์ฐ, ์ดํ ๋ค๋ฅธ ๋งํฌ๋ฅผ ๋ฐฉ๋ฌธํ์์ ๋
Referer
ํค๋์ Token ๋ ธ์ถ - ๊ธด ์ ํจ์๊ฐ์ ๊ฐ์ง CSRF Token : ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์ ํ๊ณ ๋ ๋ค ์๋ก์ด ์ธ์ ์ด ์์ฑ๋๋ ํ ํฐ์ด ์ ์ง๋์ด ๊ณต๊ฒฉ์๊ฐ ์ฌ์ฉ ๊ฐ๋ฅ
CORS Vulnerability
๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ ๋ฅผ ์ํด postMessage
, JSONP, CORS ์ ์ฑ
๊ธฐ์ ๋ฑ์ด ๋์
- ์ทจ์ฝ์ ์ ์ข
๋ฅ
- ํ์ฌ ์ฌ์ดํธ์์ ๋ค๋ฅธ ์ฌ์ดํธ๋ก ์ ๋ณด ์ ์ถ (๊ธฐ๋ฐ์ฑ) : ๋ค๋ฅธ ์ฌ์ดํธ๋ก๋ถํฐ CORS ์์ฒญ์ ๋ฐ์ ๋ ๊ทธ Origin์ ๋ํ ๊ฒ์ฌ๊ฐ ์งํ๋์ง ์๊ณ ์๋ตํ๊ฑฐ๋ Origin์ ์ ์ฝ์ด ์๋ ๊ฒฝ์ฐ
- ๋ค๋ฅธ ์ฌ์ดํธ์์ ํ์ฌ ์ฌ์ดํธ ๋ณ์กฐ (๋ฌด๊ฒฐ์ฑ) : ์ถ์ฒ์ ๋ํ ์ ๋ขฐ์ฑ์ ๋ํ ์ ํ๊ณผ XSS ํํฐ ๋ฑ ์ ๋ขฐํ์ง ์๋ ์ ๋ ฅ์ ๋ํ ๋ฐฉ์ด๊ฐ ๋ณํ
postMessage
Vulnerability
- ์ ์ : ์๋ก ๋ค๋ฅธ Origin ๊ฐ์ ๋ฉ์์ง๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋ API ๋ฐ ๋ฉ์๋.
- ๋ฉ์์ง๋ฅผ ์ ์กํ ๋์๋ ๋์ ์๋์ฐ์ postMessage๋ฅผ ํธ์ถ. ์์ ํ๋ ์๋์ฐ๋
message
์ ์ญ ์ด๋ฒคํธ๋ฅผ ํตํด ์ฒญ์ทจํ์ฌ ๋ฉ์์ง๋ฅผ ๋ฐ์ ์ ์์ - ๋ฌธ์์ด๋ฟ๋ง ์๋๋ผ ๊ฐ์ฒด๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์์.
- ํจ์, DOM ๋ ธ๋ ๊ฐ์ฒด, ํ๋กํ ํ์ ๋ฐ get/set ์์ฑ ์ ๋ณด๋ ๋ณด๋ผ์ ์์
- ๊ฐ์ฒด๋ ๋ณต์ฌ ๋ฐฉ์์ผ๋ก ์ ๋ฌํ๋ฏ๋ก ์ก์ ํ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ X
- ๋ฉ์์ง๋ฅผ ์ ์กํ ๋์๋ ๋์ ์๋์ฐ์ postMessage๋ฅผ ํธ์ถ. ์์ ํ๋ ์๋์ฐ๋
-
targetWindow.postMessage(message, targetOrigin, [transfer])
๋ณ์ ์ค๋ช targetWindow ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ๋์ Window message ๋ฉ์์ง ๊ฐ์ฒด (ํจ์, DOM ๊ฐ์ฒด ๋ฑ์ ๋ณด๋ผ ์ ์์) targetOrigin ๋ฉ์์ง ์ก์ ์์ ์ targetWindow
์ Origin์ดtargetOrigin
๊ณผ ์ผ์นํด์ผ ํจ.targetOrigin
์"*"
๋ฅผ ์ง์ ํ๋ฉด Origin ๊ฒ์ฌ๊ฐ ์ด๋ฃจ์ด์ง์ง ์์transfer (์ ํ์ฌํญ) ArrayBuffer
๋ canvas context ๋ฑ ์์ ๊ถ์ ์ ์ดํ ๊ฐ์ฒด์ ๋ฐฐ์ด์ ์ง์ -
MessageEvent
๊ณ ์ ์์ฑ ์ค๋ช origin ๋ฉ์์ง๋ฅผ ์ก์ ํ Origin ๋ฐํ source ๋ฉ์์ง๋ฅผ ์ก์ ํ Window ๊ฐ์ฒด ๋ฐํ data ๋ณต์ฌ๋ ๋ฉ์์ง ๊ฐ์ฒด ๋๋ ๊ฐ ๋ฐํ // ๋ฉ์์ง ์ก์ targetWindow.postMessage(message, targetOrigin); // ๋ฉ์์ง ์์ window.onmessage = function (e) { if (e.origin === 'https://dreamhack.io') { console.log(e.data); e.source.postMessage('Hello, world!', e.origin); } }
- Origin ์ ํ ๊ฒฝํฉ ์กฐ๊ฑด : ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ๋์์ ์ถ์ฒ๊ฐ ๊ณ ์ ๋ ์น ๋ฌธ์๊ฐ ์๋ ์ฐฝ(์๋์ฐ) ์ฐฝ์ ๊ฒฝ์ฐ์๋ ์ฌ์ฉ์๊ฐ ํ์ดํผ๋งํฌ๋ฅผ ๋ฐฉ๋ฌธํ๊ฑฐ๋ ๋ฆฌ๋ค์ด๋ ํธ ์ Origin์ด ๋ณ๊ฒฝ โ ์๋ํ์ง ์์ Origin์ผ๋ก ๋ฉ์์ง ์ ์ก
- ๊ณต๊ฒฉ ์๋๋ฆฌ์ค
- ๋ถ๋ชจ ์๋์ฐ์์ ์์ ์๋์ฐ ์์ฑ
- ์์ ์๋์ฐ๊ฐ ๋ถ๋ชจ ์๋์ฐ๋ก
postMessage
๋ก ๋ฉ์์ง ๋ฐ ๋น๋ฐ๊ฐ ์ ์ก - ๋ถ๋ชจ ์๋์ฐ๊ฐ ๊ณต๊ฒฉ์์ ๋ค๋ฅธ ์น ์ฌ์ดํธ๋ก ๋ฆฌ๋ค์ด๋ ํธ
- ์์ ์๋์ฐ๊ฐ ๊ณ์ ๋ณด๋ด๋ ๋ฉ์์ง๊ฐ ๊ณต๊ฒฉ์์ ์ฌ์ดํธ๋ก ์์
- ๊ณต๊ฒฉ ์๋๋ฆฌ์ค
JSONP Vulnerability
- Origin ๊ฒ์ฌ ๋ถ์ฌ : JSONP์ ํ์ ๋ ์ทจ์ฝ์ ์ ์๋. ํ์ง๋ง JSONP ํน์ฑ์ CSRF ๊ณต๊ฒฉ์ ๋ ์ทจ์ฝํจ
- CSRF Token ์ฌ์ฉํ์ฌ ๋ฐฉ์ด
- ์ฝ๋ฐฑ ํจ์๋ช
๊ฒ์ฆ ๋ถ์ฌ๋ก ์ธํ ์ ๊ณต์ XSS : ์ฝ๋ฐฑ๋ช
์ HTML ์ฝ๋ ๋ฑ์ ์ฝ์
ํ์ฌ HTML๋ก ์ธ์ โ XSS ์ทจ์ฝ์ ๋ฐ์
- ํํฐ ์ ์ฉ
- HTTP
Accept
ํค๋์text/javascript
MIME ํ์ ์ด ํฌํจ๋์ด ์๋ ์ง ๊ฒ์ฌ Content-Type: text/javascript
์ค์ ๋ฐX-Content-Type-Options: nosniff
ํค๋๋ก ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์๋ ๋ค๋ฅธ ์ฝํ ์ธ ๋ก ์ธ์๋๋ ๊ฒฝ์ฐ ๋ฐฉ์ง- MIME Type sniffing : ์๋ฒ์์ ๋ฐ์ Content-Type์ ์ ๋ขฐํ์ง ์๊ณ ๋ฆฌ์์ค ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ์ฌ ์ ์ ํ ํ์์ผ๋ก ํด์ํ๋ ๊ฒ.
nosniff
๋ก ์ค์ ํ์ฌ ์๋ฒ์์ ์ ๋ฌ ๋ฐ์ Content-Type ๋ง์ ๋ฏฟ์ ์ ์๋๋ก ํด์ผ ํจ
- MIME Type sniffing : ์๋ฒ์์ ๋ฐ์ Content-Type์ ์ ๋ขฐํ์ง ์๊ณ ๋ฆฌ์์ค ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ์ฌ ์ ์ ํ ํ์์ผ๋ก ํด์ํ๋ ๊ฒ.
- HTTP
- ํํฐ ์ ์ฉ
- JSONP API ์นจํด ์ฌ๊ณ ๋ฐ์ ์ ์ด์ฉ์ XSS : JSONP API๊ฐ ์นจํด ์ฌ๊ณ ๋ฅผ ๋นํด ์ ์์ ์ธ ์๋ต์ด ์ค๋ ๊ณต๊ฒฉ โ JSONP๊ฐ ์๋ CORS ์ ์ฑ ํค๋๋ฅผ ์ฌ์ฉํ๋ ์ด์
Leave a comment