본문 바로가기
프로젝트/Chrome 확장

Chrome 확장 프로그램 #2 - WebGuard QA (웹 보안 스캐너)

by 루까(Luka) 2026. 1. 31.
반응형

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 폼에 csrftoken이 이름에 포함된 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개 페이지로 구성된 대시보드를 제공한다:

  1. Overview — 전체 통계, 최근 스캔
  2. History — 검색/필터 가능한 스캔 이력
  3. Vulnerabilities — 취약점 유형별 분석 (XSS, CSRF, Headers, Sensitive Data)
  4. Reports — 심각도별 필터링 + HTML 리포트 미리보기
  5. 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

반응형