🔐 1. 서론
웹 개발을 하다 보면 보안 취약점으로 인해 사용자와 시스템이 위험에 노출될 수가 있습니다, 대표적인 웹 보안 문제로는 CROS, XSS, CSRF가 있으며 각각의 원리와 방어 방법에 대해 이해하는 것이 가장 중요합니다. 이번 개념을 통해 로컬 환경에서 직접 실습하며 다음과 같은 개념을 확인할 수 있습니다.
- 왜 이런 공격이 발생하는가
- 어떤 방식으로 확인이 가능한가
- 어떻게 방어할 수 있는가
🔐 2. CORS 실습
브라우저는 기본적으로 동일 출처 정책(SOP)를 적용하여 다른 출처에서 요청을 하게되면 자동으로 차단됨니다 이것을 서버에서 CORS 헤더로 직접 허용해줘야 합니다.
🌚 환경 세팅
mkdir cxf-test
cd cxf-test
npm init -y
npm install express cors
nodejs 세팅이 완료되었다면 프로젝트 루트 폴더안에 index.js를 생성하고 다음과 같은 코드를 작성합니다.
const express = require("express");
const app = express();
app.get("/api/data", (req, res) => res.json({ message: "CORS Test " }));
app.listen(4000);
이제 이것을 바탕으로 직접 웹 사이트 공격을 해보겠습니다. 프로젝트 루트에 index.html을 생성해 다음과 같은 코드를 만듭니다.
<button id="fetchBtn">데이터 가져오기</button>
<pre id="result"></pre>
<script>
document.getElementById("fetchBtn").onclick = async () => {
try {
const res = await fetch("http://localhost:4000/api/data", {
credentials: "include",
});
const data = await res.json();
document.getElementById("result").innerText = JSON.stringify(data);
} catch (err) {
console.error("에러발생:", err);
}
};
</script>
🔐공격 확인
- 브라우저 콘솔 -> CORS 에러 발생
- 네트워크 탭 -> 서버 응답은 정상이나 브라우저가 차단한 것
🔐 방어 적용
const express = require("express");
const cors = require("cors");
const app = express();
// 방어 적용
const allowedOrigin = "http://127.0.0.1:5500";
app.use(
cors({
origin: allowedOrigin,
credentials: true,
})
);
app.get("/api/data", (req, res) => res.json({ message: "CORS Test " }));
app.listen(4000, () => console.log("Server is running port 4000"));
- origin -> 브라우저에서 HTML을 열 때 origin으로 정확히 맞춤
- credentials: true -> 쿠키/세션 포함 요청 허용
🔐 방어 확인
- 브라우저 HTML에서 버튼 클릭 -> JSON 출력 정상 확인
- 브라우저 콘솔 -> 에러 없음
항목 | 설명 |
SOP | 브라우저 기본 정책, 다른 origin 요청 차단 |
CORS | 서버에서 허용 origin과 credentials 헤더 설정 필요 |
origin | 브라우저에서 요청하는 URL과 서버 허용 URL이 정확히 일치해야함 |
credentials | 쿠키/세션 포함 요청 시 true 설정 필요, '*'와 동시에 불가 |
🔐 3. XSS 실습
XSS(Cross-Site Scripting)은 공격자가 악성 스크립트를 웹페이지에 삽입하고 그것을 사용자의 브라우저에 실행하도록 하는 것입니다.
- 목적: 쿠키 탈취, 세션 하이재킹, 화면 변조 등
- 종류
- Reflected XSS: 사용자가 입력한 값이 바로 페이지에 반영될 때 발생
- Stored XSS: 공격 스크립트가 DB에 저장되어 여러 사용자가 접속 시 실행
- DOM-based XSS: 클라이언트 사이드 JS에서 직접 DOM을 조작하며 발생
🛜 환경 세팅
mkdir xss-test
cd xss-test
npm init -y
npm install express body-parser
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", (req, res) => {
res.send(`
<form method="POST" action="/echo">
<input name="msg" />
<button>전송</button>
</form>
`);
});
app.post("/echo", (req, res) => {
const msg = req.body.msg;
// 필터링 없이 바로 출력 -> 취약점
res.send(`<h1>입력 메시지: </h1><p>${msg}</p>`);
});
app.listen(4001, () => console.log("XSS Test Server running on port 4001"));
🔐 공격 확인
- 입력창에 <script>alert("XSS")</script> XSS 입력
- 제출 시 브라우저에서 팝업 발생 -> XSS 성공
🔐 방어 적용
const escapeHtml = (str) =>
str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
app.post("/echo", (req, res) => {
const msg = escapeHtml(req.body.msg);
// 필터링 없이 바로 출력 -> 취약점, => 방어적용후 <script>alert("XSS")</script>
res.send(`<h1>입력 메시지: </h1><p>${msg}</p>`);
});
🔐 4. CSRF 실습
CSRF(Cross-Site Request Forgery)는 사용자가 로그인된 상태에 공격자가 만든 요청을 보내 사용자의 권한으로 악의적인 동작을 수행합니다.
🛜 환경 세팅
mkdir csrf-test
cd csrf-test
npm init -y
npm install express cookie-parser body-parser
const express = require("express");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
// 로그인 상태 가정
app.get("/login", (req, res) => {
res.cookie("auth", "123");
res.send("로그인 완료");
});
// 취약한 이메일 변경
app.post("/change-email", (req, res) => {
const newEmail = req.body.email;
// CSRF 취약: auth 쿠키 체크만, 쿠키 X
res.send(`이메일이 ${newEmail}로 변경되었습니다.`);
});
app.listen(4003, () =>
console.log("CSRF Email Test Server is running on port 4003")
);
🔐 공격 확인
<form action="http://localhost:4003/change-email" method="POST">
<input type="hidden" name="email" value="attacker@example.com" />
<input type="submit" value="Click me!" />
</form>
- 사용자가 로그인 상태에서 공격 페이지를 열고 클릭 -> 이메일이 공격자 주소를 변경함
- CSRF 성공
🔐 방어 적용 (CSRF 토큰 사용)
const csrf = require("csurf"); // yarn add csurf && npm install csurf
app.use(cookieParser());
app.use(csrf({ cookie: true }));
// 방어 적용
app.get("/change-email-form", (req, res) => {
res.send(`
<form method="POST" action="/change-email">
<input name="email" />
<input type="hidden" name="_csrf" value="${req.csrfToken()}" />
<button>이메일 변경</button>
</form>
`);
});
// 취약한 이메일 변경
app.post("/change-email", (req, res) => {
const newEmail = req.body.email;
// CSRF 취약: auth 쿠키 체크만, 쿠키 X
res.send(`이메일이 ${newEmail}로 변경되었습니다.`);
});
🛜 핵심 포인트
항목 | 설명 |
CSRF 공격 | 로그인 상태 사용자의 권한을 도용해 요청 수행 |
취약점 | 세션 쿠키만 확인, CSRF 토큰 없음 |
방어 | CSRF 토큰 적용 -> 공격 페이지에서 요청 불가 |
실습 | 이메일 변경, 계정 설정 등 |
GitHub - Koras02/CORS-XSS-CSRF
Contribute to Koras02/CORS-XSS-CSRF development by creating an account on GitHub.
github.com
'웹' 카테고리의 다른 글
[알고리즘] 난수란? (1) | 2025.08.31 |
---|---|
[Web] SSR이란? 서버 사이드 렌더링 (0) | 2025.03.01 |
[Web] 인터넷 프로토콜의 종류 (0) | 2025.02.27 |
[Web] 상태코드란? (0) | 2025.02.27 |
[Web] 개발자의 종류에 관해 (0) | 2025.02.23 |