はじめに
こんにちは!最近、手元のミニPC(NucBox)でコンテナ技術やセキュリティツールをいじり倒すのにハマっています。
今回は、「脆弱性だらけのやられアプリ」と「それを攻撃・診断するツール」、さらに「見つかった脆弱性を可視化するダッシュボード」を、Docker Composeを使ってたった1つのファイルでローカルに構築する方法をご紹介します。
セキュリティの勉強を始めたい初心者の方や、DevSecOpsの雰囲気を味わってみたい方にピッタリの「おうちサイバーレンジ(演習環境)」です!
全体構成図

🏗️ docker-compose.yml の作成
まずは、テスト対象のアプリと管理ツール群を一気に立ち上げるための設計図を作成します。適当な作業用ディレクトリ(今回は ~/projects/siem3300)を作り、以下の docker-compose.yml を保存してください。
YAML
name: sec-lab
services:
# ==========================================
# 1. 監視対象・テスト環境(やられ側)
# ==========================================
# フロントエンドのWebサーバー
target-frontend:
image: nginx:alpine
container_name: target-frontend
ports:
- "4300:80"
# バックエンドのデータベース(後でダッシュボードのデータ元になります)
target-db:
image: postgres:15-alpine
container_name: target-db
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: StrongPassword123!
POSTGRES_DB: target_app_db
ports:
- "4301:5432"
# 意図的に脆弱性が作り込まれたECサイト「OWASP Juice Shop」
juice-shop:
image: bkimminich/juice-shop:latest
container_name: juice-shop
ports:
- "4302:3000"
# ==========================================
# 2. セキュリティ管理・診断環境(守る・攻める側)
# ==========================================
# 脆弱性を見やすく可視化するためのBIツール
metabase:
image: metabase/metabase:latest
container_name: metabase
ports:
- "4305:3000"
# Webアプリケーション脆弱性スキャナ「OWASP ZAP」
owasp-zap:
image: zaproxy/zap-stable:latest
container_name: owasp-zap
# スキャン完了後もコンテナを落とさず常駐させるためのおまじない
command: tail -f /dev/null
ports:
- "4306:8080"
volumes:
# 手元の zap_wrk フォルダに診断レポートを出力させるためのマウント設定
- ./zap_wrk:/zap/wrk
ファイルができたら、以下のコマンドで一斉起動します!
# -d オプションでバックグラウンド起動します
docker compose up -d
🔍 OWASP ZAPで脆弱性スキャンを実行!
環境が立ち上がったら、常駐させている owasp-zap コンテナの中から、やられアプリ(juice-shop)に向けて自動診断(ベースラインスキャン)を仕掛けます。
※事前にレポート出力用のフォルダを作っておきます。
mkdir -p zap_wrk
chmod 777 zap_wrk
スキャン実行コマンドはこちら!
docker exec -it owasp-zap zap-baseline.py -t http://juice-shop:3000 -r zap_report.html -I
zap-baseline.py: 数分で終わる軽量なベースラインスキャンを実行するスクリプト。-t http://juice-shop:3000: 攻撃対象のURL。Dockerの内部ネットワークなので、コンテナ名で直接アクセスできます。-r zap_report.html: スキャン結果をHTMLレポートとして出力。-I: エラーが出ても途中で止めずに最後まで完走させるオプション。
(裏側のお話)ZAPの設定ファイルの中身
ちなみに、このスキャンが走っているとき、出力先フォルダには zap.yaml という設定ファイルが自動生成されます。中身を覗いてみると……
# zap.yaml の中身(抜粋)
env:
contexts:
- excludePaths: []
name: baseline
urls:
- http://juice-shop:3000 # ターゲットがしっかり設定されています
jobs:
- parameters:
maxDuration: 1
url: http://juice-shop:3000
type: spider # 1分間のクローリング(サイト内のリンク巡回)
- parameters:
reportDir: /zap/wrk/
reportFile: zap_report.html
template: traditional-html
type: report # 最後にHTMLレポートを生成するジョブ
このように、ZAPが裏でどんなジョブ(Spiderでの巡回やレポート生成)を動かしているかが分かります。
📊 Metabaseで「経営層向けダッシュボード」を作る
ZAPからHTMLのレポートは出ましたが、実務では**「そのデータをどう可視化して、どうリスク判断するか」**が重要です。
そこで、先ほど立ち上げた target-db (PostgreSQL) に、診断で見つかった想定のダミーデータを流し込んでみます!
Bash
# target-db コンテナに入って、psqlコマンドでSQLを直接実行!
david@NucBoxK5:~/projects/siem3300$ docker exec -i target-db psql -U admin -d target_app_db -c "
-- 1. 脆弱性データを格納するテーブルを作成
CREATE TABLE IF NOT EXISTS vulnerabilities (
id SERIAL PRIMARY KEY,
system_name VARCHAR(50),
vulnerability_name VARCHAR(100),
severity VARCHAR(20),
cvss_score NUMERIC(3,1),
status VARCHAR(20),
detected_date DATE
);
-- 2. テーブルの中身を一旦リセット
TRUNCATE TABLE vulnerabilities;
-- 3. ZAP等で見つかった想定の脆弱性データを8件インサート
INSERT INTO vulnerabilities (system_name, vulnerability_name, severity, cvss_score, status, detected_date) VALUES
('Juice Shop (EC)', 'Content Security Policy (CSP) Not Set', 'Medium', 5.5, 'Open', CURRENT_DATE),
('Juice Shop (EC)', 'Cross-Domain JS Inclusion', 'Low', 3.0, 'Open', CURRENT_DATE),
('Juice Shop (EC)', 'SQL Injection (Login)', 'Critical', 9.8, 'Closed', CURRENT_DATE - 10),
('Juice Shop (EC)', 'Reflected XSS', 'High', 7.5, 'In Progress', CURRENT_DATE - 3),
('Internal CRM', 'Outdated OpenSSL (Heartbleed)', 'Critical', 9.0, 'Open', CURRENT_DATE - 15),
('Internal CRM', 'Weak Password Policy', 'Medium', 4.5, 'Closed', CURRENT_DATE - 30),
('HR System', 'Directory Traversal', 'High', 8.2, 'Open', CURRENT_DATE - 5),
('HR System', 'Information Disclosure', 'Low', 2.5, 'In Progress', CURRENT_DATE - 2);
"
このコマンドを実行すると、CREATE TABLE、TRUNCATE TABLE、INSERT 0 8 と表示され、無事にデータベースに脆弱性リストが格納されます。
ダッシュボードの完成!
あとは、ブラウザで http://localhost:4305 にアクセスして Metabase を開き、先ほどの PostgreSQL に接続するだけです。 Metabaseの「質問(Question)」機能を使ってデータを円グラフや棒グラフにまとめれば……
ただツールを動かすだけでなく、「データの流れ」や「可視化」までを一気通貫で学べるこの環境、ぜひ皆さんもローカルで試してみてくださいね。
