[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 헤더 이해하기
웹 보안의 기본: XSS와 CSRF 최종정리 🔒
1. XSS (Cross-Site Scripting) 란?
해커가 웹사이트에 악성 스크립트를 심어 다른 사용자를 공격하는 방법
- CSS와 이름이 겹쳐서 Cross(X)와 Site Scripting(SS)를 따와 XSS로 명명
XSS 공격 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. 해커의 악성 댓글
const 악성댓글 = `
상품 좋아요!
<script>
// 사용자 정보를 해커에게 전송하는 코드
해커사이트로전송(document.cookie);
</script>
`;
// 2. 위험한 처리 방식 (❌)
댓글영역.innerHTML = 악성댓글; // 악성 스크립트 실행됨!
// 3. 안전한 처리 방식 (✅)
댓글영역.textContent = 악성댓글; // 텍스트로만 표시
2. CSRF (Cross-Site Request Forgery) 란?
해커가 사용자를 속여서 의도치 않은 동작을 하게 만드는 공격
CSRF 공격 예시
1
2
3
4
5
6
7
8
9
10
11
// 1. 정상적인 송금 기능
function 일반송금(계좌, 금액) {
fetch("/api/송금", {
method: "POST",
body: JSON.stringify({ 계좌, 금액 }),
});
}
// 2. 해커의 피싱 사이트
// "당신의 고양이가 너무 귀여워요!" 클릭시 실행되는 코드
자동송금("해커계좌", "1000000"); // 사용자도 모르게 송금됨!
3. 방어 방법 🛡️
1) XSS 방어
1
2
3
4
5
6
7
8
9
10
11
12
// 1. textContent 사용하기
element.textContent = 사용자입력;
// 2. 특수문자 치환하기
function 안전한텍스트만들기(위험한텍스트) {
return 위험한텍스트
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
2) CSRF 방어
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1. 안전한 API 요청
async function 안전한송금(계좌, 금액) {
const 보안토큰 = document.querySelector('meta[name="csrf-token"]').content;
await fetch("/api/송금", {
method: "POST",
headers: {
"Content-Type": "application/json",
"CSRF-Token": 보안토큰, // 보안 토큰 추가
},
credentials: "include", // 쿠키 포함
body: JSON.stringify({
계좌: 계좌,
금액: 금액,
}),
});
}
4. 실제 적용 예시
1) 게시판 댓글 시스템
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class 안전한댓글시스템 {
// 댓글 표시하기
댓글표시(댓글내용) {
// XSS 방어: innerHTML 대신 textContent 사용
댓글영역.textContent = 댓글내용;
}
// 댓글 작성하기
async 댓글작성(내용) {
const 보안토큰 = this.보안토큰가져오기();
// CSRF 방어: 보안 토큰 포함
await fetch("/api/댓글작성", {
method: "POST",
headers: {
"CSRF-Token": 보안토큰,
},
body: JSON.stringify({ 내용 }),
});
}
}
5. 핵심 정리 ✨
-
XSS 기억하기
- 사용자 입력을 그대로 HTML에 넣지 않기
innerHTML
대신textContent
사용하기- 필요하면 특수문자 치환하기
-
CSRF 기억하기
- 중요한 동작에는 보안 토큰 사용하기
- 토큰 검증 없이 중요 동작 실행하지 않기
- 로그인 상태 확인하기
-
일반적인 보안 수칙
- 사용자 입력은 항상 위험하다고 생각하기
- 중요한 동작은 반드시 검증하기
- 보안은 여러 단계로 구현하기