글보기 보안
블로그 글보기 기능을 구현할 때에는 게시글을 안전하게 표시하려면 보안 조치가 필요합니다.
1. XSS(크로스 사이트 스크립팅) 공격 방지
문제점
사용자가 <script>alert('해킹됨!')</script> 같은 악성 스크립트를 입력하면, 브라우저에서 그대로 실행될 수 있음.
-> 방문자의 개인정보 탈취, 피싱, 악성 코드 실행 등의 보안 문제 발생
해결 방법
- sanitize-html 같은 HTML 필터링 라이브러리 사용
- Vue의 v-html을 직접 사용하지 않거나, 반드시 필터링 후 사용
import sanitizeHtml from "sanitize-html";
const safeHtml = sanitizeHtml(userInput, {
allowedTags: ["b", "i", "strong", "a", "p", "ul", "li", "h1", "h2"],
allowedAttributes: { a: ["href", "title"], img: ["src", "alt"] }
});
- 주의: v-html을 사용할 경우, 반드시 sanitize-html로 필터링해야 함.
<template>
<div v-html="safeHtml"></div> <!-- v-html 사용 시 보안 강화 필수 -->
</template>
<script>
export default {
data() {
return {
safeHtml: sanitizeHtml("<script>alert('XSS');</script><p>안전한 텍스트</p>")
};
}
};
</script>
- 악성 <script> 태그 제거 → 안전한 HTML만 표시
2. SQL Injection 방지 (백엔드 사용 시)
문제점
SQL 데이터를 직접 조회할 때 사용자 입력이 SQL 문으로 실행될 가능성이 있음.
SELECT * FROM posts WHERE id = '1' OR '1' = '1'
위 코드처럼 항상 참이 되는 조건이 들어가면 모든 데이터가 노출될 수 있음.
해결 방법
- 파이어스토어 사용 시 Firestore Security Rules 적용
- SQL을 사용할 경우 ORM(예: Prisma, Sequelize) 또는 Prepared Statement 사용
// SQL Injection 방지 (예제: MySQL + Node.js)
const query = "SELECT * FROM posts WHERE id = ?";
db.query(query, [userInput]); // 바인딩 처리로 SQL Injection 방지
- 직접 문자열을 연결하지 않고, 안전하게 처리
3. API 엔드포인트 보안 (인증 & 권한 설정)
문제점
블로그 글을 조회하는 API가 인증 없이 열려 있으면 비공개 글이 노출될 위험이 있음.
해결 방법
- Firebase Firestore 보안 규칙 설정
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if resource.data.isPublic == true || request.auth != null;
}
}
}
- isPublic == true인 경우에만 비로그인 사용자도 조회 가능
- 로그인한 사용자만 글을 볼 수 있도록 설정 가능
4. CORS(Cross-Origin Resource Sharing) 보안
문제점
API가 모든 도메인에서 접근 가능하면, 악성 사이트에서 데이터를 요청할 수 있음.
해결 방법
- CORS 설정에서 신뢰할 수 있는 도메인만 허용
// Node.js Express CORS 설정 (보안 강화)
const cors = require("cors");
app.use(cors({
origin: ["https://myblog.com"], // 허용할 도메인만 지정
methods: ["GET"], // 글 조회만 허용
credentials: true
}));
5. 로그인 기반 글 조회 제한
문제점
비회원이 유료 게시물 또는 관리자 전용 글을 조회할 수 있음.
해결 방법
- Firebase Authentication + Firestore Security Rules 적용
- Vue Router에서 로그인 여부 확인 후 페이지 접근 제한
router.beforeEach((to, from, next) => {
const isAuthenticated = !!firebase.auth().currentUser;
if (to.meta.requiresAuth && !isAuthenticated) {
next("/login");
} else {
next();
}
});
- requiresAuth: true인 페이지는 로그인된 사용자만 접근 가능
6. HTTPS 사용
문제점
HTTP를 사용하면 로그인 정보, API 요청 데이터가 평문으로 노출될 위험이 있음.
해결 방법
- HTTPS를 강제 사용 (Let's Encrypt, Cloudflare 활용)
- HSTS(HTTP Strict Transport Security) 설정
server {
listen 443 ssl;
server_name myblog.com;
ssl_certificate /etc/letsencrypt/live/myblog.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myblog.com/privkey.pem;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
- HTTP → HTTPS 자동 리디렉션
7. 데이터 무결성 보호
문제점
사용자가 API 요청을 변조하여 다른 사용자의 게시글을 수정/삭제할 가능성이 있음.
해결 방법
- Firestore Rules에서 본인 글만 수정 가능하도록 설정
match /posts/{postId} {
allow update, delete: if request.auth.uid == resource.data.authorId;
}
- 로그인된 사용자의 UID와 게시글 작성자의 UID가 동일한 경우에만 수정 가능
8. 속도 및 성능 보안
문제점
트래픽 폭주 시 서비스가 마비될 가능성이 있음.
해결 방법
- 캐싱(Cache-Control) 사용
- Firebase Firestore의 limit() 사용하여 과도한 쿼리 방지
const q = query(collection(db, "posts"), orderBy("createdAt", "desc"), limit(10));
- Cloudflare, AWS WAF 같은 웹 방화벽(WAF) 활용
결론
보안 이슈해결 방법
XSS 공격 | sanitize-html 사용, v-html 최소화 |
SQL Injection | ORM, Prepared Statement 사용 |
API 보안 | Firebase Security Rules 적용 |
CORS 설정 | 신뢰할 도메인만 허용 |
로그인 필요 | router.beforeEach() 활용 |
HTTPS | SSL 인증서 적용, HSTS 활성화 |
데이터 보호 | 본인 글만 수정 가능하도록 보안 규칙 설정 |
속도 최적화 | 캐싱, Firestore limit() 사용 |
sanitize-html란?
sanitize-html은 HTML 보안을 위해 사용되는 JavaScript 라이브러리입니다.
이 라이브러리는 사용자로부터 입력받은 HTML을 필터링하여 XSS(Cross-Site Scripting) 공격을 방지합니다.
왜 sanitize-html이 필요한가?
사용자가 입력한 HTML을 그대로 렌더링하면 악성 스크립트 공격이 가능합니다.
- sanitize-html을 사용하면 악성 스크립트를 자동으로 제거합니다.
sanitize-html 설치
npm install sanitize-html
사용법
기본 사용 예제
const sanitizeHtml = require("sanitize-html");
const dirty = '<script>alert("해킹됨!");</script><h1>안전한 제목</h1>';
const clean = sanitizeHtml(dirty);
console.log(clean); // "<h1>안전한 제목</h1>"
- <script> 태그가 제거됨 → 보안 강화!
허용할 태그 지정하기
기본적으로 모든 스크립트 관련 태그는 제거되지만, 특정 태그만 허용할 수도 있습니다.
const clean = sanitizeHtml(dirty, {
allowedTags: ["b", "i", "em", "strong", "h1"], // 허용할 태그 지정
});
console.log(clean); // "<h1>안전한 제목</h1>"
- script는 제거되고, h1 태그는 유지됨
허용할 속성 지정하기
img, a 등의 태그는 특정 속성만 허용하는 것이 안전합니다.
const clean = sanitizeHtml(dirty, {
allowedTags: ["a", "img"],
allowedAttributes: {
a: ["href", "title"],
img: ["src", "alt"]
}
});
- 링크와 이미지의 속성을 제한하여 악성 코드 방지
필터링된 태그를 다른 값으로 변환
sanitize-html을 사용하면 제거된 태그를 특정 텍스트로 변환할 수도 있습니다.
const clean = sanitizeHtml(dirty, {
transformTags: {
"script": () => ({
tagName: "div",
text: "[스크립트 제거됨]"
})
}
});
console.log(clean); // "[스크립트 제거됨] <h1>안전한 제목</h1>"
- 스크립트가 제거되지 않고 특정 문구로 변환됨
결론
sanitize-html은 사용자 입력을 필터링하여 XSS 공격을 방지하는 강력한 도구입니다.
-> 보안이 중요한 웹사이트(예: 블로그, 게시판, 채팅)에서 필수적으로 사용해야 합니다.
'토이 프로젝트 - Vue, Firebase로 서버리스 PWA 개발' 카테고리의 다른 글
17. Firestore로 PWA myBlog 개발 - 블로그 글 상세보기 기능들 (0) | 2025.02.21 |
---|---|
16. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - 홈페이지 (0) | 2025.02.20 |
14. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - 블로그 글쓰기 (0) | 2025.02.14 |
13. Vue(with Vuetify)와 Firebase로 서버리스 PWA myBlog 개발 - 블로그 카테고리 (0) | 2025.02.14 |
12. Vue(with Vuetify)와 Firebase로 PWA myBlog 개발 - OAuth 구글 계정으로 로그인 (0) | 2025.02.13 |