Chrome 확장 프로그램 — WebGuard QA
왜 만들었나
QA 업무를 하면서 배포 전에 기본적인 보안 체크를 할 일이 많다. XSS 취약점은 없는지, CSRF 토큰은 달려 있는지, API 키가 프론트엔드에 노출되어 있지는 않은지.
매번 수동으로 소스를 훑어보는 건 비효율적이다. Burp Suite 같은 전문 도구는 무겁고 학습 곡선이 높다. 간단하게 "이 페이지 한번 스캔해봐"하면 주요 취약점을 잡아주는 도구가 필요했다.
그래서 Chrome 확장 프로그램으로 만들었다. Ticket Timer에 이어 두 번째 확장이다.
Chrome Web Store: WebGuard QA 설치하기
검사 항목
Quick Scan (1~3초)
4가지 핵심 검사를 빠르게 수행한다.
1. XSS 탐지
// 인라인 이벤트 핸들러 검출
document.querySelectorAll('[onclick], [onload], [onerror], [onmouseover]')
// eval() 사용 검출 — Critical 등급
const scripts = document.querySelectorAll('script');
scripts.forEach(script => {
if (script.textContent.includes('eval(')) {
// Critical: eval() 사용 발견
}
});
eval()이 있으면 Critical, 인라인 핸들러는 High로 분류한다.
2. CSRF 검증
// POST 폼에서 CSRF 토큰 필드 존재 여부 확인
const forms = document.querySelectorAll('form[method="post"]');
forms.forEach(form => {
const hasToken = form.querySelector(
'input[name*="csrf"], input[name*="token"], input[name="_token"]'
);
if (!hasToken) {
// High: CSRF 토큰 누락
}
});
POST 폼에 csrf나 token이 이름에 포함된 input이 없으면 경고한다.
3. 보안 헤더
CSP(Content-Security-Policy)와 X-Frame-Options의 존재 여부를 체크한다. Content Script에서는 HTTP 응답 헤더를 직접 읽을 수 없어서 <meta> 태그 기반으로 검사한다.
4. 민감 정보 노출
// 페이지 본문에서 패턴 매칭
const bodyText = document.body.textContent;
// API 키 패턴
bodyText.match(/api[_-]?key[_-]?[:=]\s*['"]?[a-zA-Z0-9]{20,}['"]?/gi);
// 이메일 패턴
bodyText.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g);
// HTML 주석에 민감 정보
const comments = document.evaluate('//comment()', document, ...);
API 키가 프론트엔드 소스에 노출되어 있으면 Critical이다.
Deep Scan (3~10초)
Quick Scan에 3가지를 추가한다:
- DOM 보안 — HTTP 스크립트 로딩,
document.write사용 - JavaScript 분석 — 과도한
console.log(5개 이상이면 경고) - 쿠키 검사 —
document.cookie존재 여부 (HttpOnly/Secure 플래그는 JS에서 확인 불가)
심각도 분류
| 등급 | 예시 | 색상 |
|---|---|---|
| Critical | eval() 사용, API 키 노출 |
빨강 |
| High | CSRF 토큰 누락, 인라인 이벤트 핸들러 | 주황 |
| Medium | CSP 미설정, 사용자 입력 관련 | 노랑 |
| Low | HTTP 링크, 과도한 console.log | 파랑 |
| Pass | 검사 통과 | 초록 |
아키텍처
Popup (popup.js)
↓ chrome.scripting.executeScript()
Content Script (content-script.js)
↓ DOM 분석 → 결과 반환
↓ chrome.runtime.sendMessage()
Service Worker (service-worker.js)
↓ 히스토리 저장 + 알림
Dashboard (dashboard.js)
↓ 통계 + 리포트 생성
핵심 패턴은 동적 Content Script 주입이다. Ticket Timer는 host_permissions로 특정 URL에 접근했지만, WebGuard QA는 activeTab 권한만으로 현재 탭에 스크립트를 주입한다.
// popup.js — 스캔 시 Content Script 동적 주입
await chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ['content/content-script.js']
});
// 주입 후 메시지 전송
const response = await chrome.tabs.sendMessage(tab.id, {
action: 'quickScan',
options: { xss: true, csrf: true, headers: true, sensitiveData: true }
});
activeTab만 쓰는 이유는 Chrome Web Store 심사 때문이다. 초기에 <all_urls>를 요청했다가 권한이 과도하다는 피드백을 받고 activeTab으로 변경했다. 사용자가 클릭한 탭에서만 동작하므로 보안적으로도 맞다.
리포트 시스템
스캔 히스토리
최근 100건의 스캔 결과를 chrome.storage.local에 저장한다.
// service-worker.js
async function saveScanResult(url, title, results) {
const { scanHistory = [] } = await chrome.storage.local.get('scanHistory');
scanHistory.unshift({
id: Date.now(),
url, title,
timestamp: new Date().toISOString(),
results,
summary: generateSummary(results) // critical/high/medium/low 카운트
});
if (scanHistory.length > 100) scanHistory.length = 100;
await chrome.storage.local.set({ scanHistory });
}
대시보드
5개 페이지로 구성된 대시보드를 제공한다:
- Overview — 전체 통계, 최근 스캔
- History — 검색/필터 가능한 스캔 이력
- Vulnerabilities — 취약점 유형별 분석 (XSS, CSRF, Headers, Sensitive Data)
- Reports — 심각도별 필터링 + HTML 리포트 미리보기
- Settings — 자동 스캔 ON/OFF
JSON 내보내기
// 스캔 결과를 JSON으로 다운로드
const dataStr = JSON.stringify(scanResult, null, 2);
const blob = new Blob([dataStr], { type: 'application/json' });
await chrome.downloads.download({
url: URL.createObjectURL(blob),
filename: `webguard-scan-${timestamp}.json`,
saveAs: true
});
Critical 이슈 알림
Critical 등급의 취약점이 발견되면 브라우저 알림을 자동으로 띄운다.
// service-worker.js
const criticalIssues = results.filter(r => r.severity === 'critical');
if (criticalIssues.length > 0) {
chrome.notifications.create({
type: 'basic',
title: 'WebGuard QA - 보안 경고',
message: `${title}에서 ${criticalIssues.length}개의 심각한 보안 문제가 발견되었습니다.`,
priority: 2
});
}
한계
솔직히 이건 전문 보안 도구가 아니다. 알고 있어야 할 한계:
- HTTP 응답 헤더를 읽을 수 없다 — Content Script의 제약. 메타 태그만 검사
- HttpOnly/Secure 쿠키 플래그 확인 불가 — JavaScript에서 접근 자체가 불가능
- 정적 패턴 매칭 — 실제 코드 실행 분석이 아닌 패턴 기반 검출
- CSP 실효성 검증 불가 — 존재 여부만 확인, 실제 동작은 미검증
하지만 "배포 전에 기본적인 것들은 걸러주는" 용도로는 충분하다. Burp Suite를 돌리기 전에 빠르게 한번 훑어보는 느낌이다.
Ticket Timer와의 비교
| 항목 | Ticket Timer | WebGuard QA |
|---|---|---|
| 권한 | host_permissions (Google, Cloudflare) |
activeTab + scripting |
| 스크립트 | 팝업에서 직접 처리 | Content Script 동적 주입 |
| 저장 | 탭별 타이머 | 스캔 히스토리 100건 |
| 알림 | 타이머 만료 시 | Critical 취약점 발견 시 |
| 대시보드 | 없음 | 5페이지 분석 대시보드 |
두 번째 확장을 만들면서 느낀 건, 첫 번째에서 배운 Manifest V3 구조와 Chrome API 패턴이 거의 그대로 재활용된다는 것이다. 진입장벽은 첫 번째가 높고, 두 번째부터는 빠르다.
마무리
QA 업무에서 실제로 쓰려고 만든 도구다. 실무에서 반복하던 수동 체크를 자동화했다는 점에서 만족도가 높다. Chrome Web Store에 배포 완료했고, 누구나 설치해서 사용할 수 있다.
기술 스택: Vanilla JavaScript, Chrome Extension APIs (Manifest V3), Content Script
소스 코드: GitHub
Chrome Web Store: WebGuard QA
'프로젝트 > Chrome 확장' 카테고리의 다른 글
| Chrome 확장 프로그램 #1 - Ticket Timer (티켓팅 타이머) (0) | 2026.01.28 |
|---|