はじめに
Webセキュリティは、脆弱性の種類や攻撃手法を読んで覚えるだけでは身につきにくいです。
実際に手を動かして、自分の手でSQLインジェクションを通したり、XSSを発火させたりして初めて、対策の意味が理解できると思います。
そのための教材として、意図的に脆弱性を仕込んだWebアプリケーションが世界中で使われています。
今回、その中から4つを選び、Dockerでローカルに構築しました。
- OWASP Juice Shop
- WebGoat
- DVWA(Damn Vulnerable Web Application)
- OWASP crAPI
構築だけで終わらせず、この4つをいつでも作り直せるよう、Claude Code向けのSkillとして自動化もしてみました。
この記事では、実際に構築した4つの環境を画面つきで紹介し、続けてSkillの中身、他のツールの探し方、Dockerを使わずブラウザだけで学習できるサービスの順に紹介していきます。
4つの学習環境
紹介する4つは、いずれも「意図的に脆弱性を仕込んだWebアプリケーション」という共通点を持ちながら、対象とする技術スタックや学び方の形式が異なります。
一つずつ、概要と実際の画面、構築方法を見ていきます。
OWASP Juice Shop
Juice ShopはNode.js製のECサイトを模したアプリケーションで、OWASP Top 10に含まれるほぼすべてのカテゴリの脆弱性を、スコアボード形式のチャレンジとして体験できます。
モダンなSPAの見た目をしているのが特徴で、今も開発が活発に続いています。
構築は公式のDockerイメージをそのまま使うだけで済みました。
services:
juice-shop:
image: bkimminich/juice-shop:latest
container_name: juice-shop
ports:
- "127.0.0.1:3000:3000"
restart: unless-stopped
docker compose up -d
起動後、http://localhost:3000 にアクセスすると、上の画像のような商品一覧のトップページが表示されます。
ここから会員登録やログインを進めていくと、価格改ざんやアカウント乗っ取りといったチャレンジに取り組めるようになります。
今回構築した4つの中で、Juice Shopだけは特に詰まる点がありませんでした。
公式リポジトリ: https://github.com/juice-shop/juice-shop
WebGoat
WebGoatはOWASP製のJavaアプリケーションで、レッスン形式で一つずつ脆弱性を学んでいく構成になっています。
攻撃対象のWebGoat本体に加えて、攻撃者側の役割を担うWebWolfという別アプリが同梱されている点が特徴で、フィッシングメールの送信や受信ファイルの模擬など、攻撃側の視点も体験できます。
services:
webgoat:
image: webgoat/webgoat:latest
container_name: webgoat
environment:
- TZ=Asia/Tokyo
ports:
- "127.0.0.1:8080:8080"
- "127.0.0.1:9090:9090"
restart: unless-stopped
WebGoat本体は http://localhost:8080/WebGoat、WebWolfは http://localhost:9090/WebWolf でアクセスします。
起動直後は docker ps 上で unhealthy と表示されることがありますが、Javaアプリの初期化が終わっていないだけなので、少し待てば正常に応答するようになります。
公式リポジトリ: https://github.com/WebGoat/WebGoat
DVWA(Damn Vulnerable Web Application)
DVWAはPHP/MariaDB製の学習アプリで、脆弱性ごとの難易度をlow、medium、high、impossibleの4段階に切り替えられるのが特徴です。
同じ脆弱性でも対策の強さによって攻撃が通ったり通らなかったりするので、対策の効き方を比較しながら学べます。
volumes:
dvwa:
networks:
dvwa:
services:
dvwa:
image: ghcr.io/digininja/dvwa:latest
container_name: dvwa
environment:
- DB_SERVER=db
depends_on:
- db
networks:
- dvwa
ports:
- "127.0.0.1:4280:80"
restart: unless-stopped
db:
image: docker.io/library/mariadb:10
container_name: dvwa-db
environment:
- MYSQL_ROOT_PASSWORD=dvwa
- MYSQL_DATABASE=dvwa
- MYSQL_USER=dvwa
- MYSQL_PASSWORD=p@ssw0rd
volumes:
- dvwa:/var/lib/mysql
networks:
- dvwa
restart: unless-stopped
このcompose定義は、公式リポジトリのcompose.ymlをもとに、ローカルにDVWAのソースコードを持たない前提でbuild: .の指定を外し、ビルド済みイメージ(ghcr.io/digininja/dvwa:latest)を直接pullする形に変えたものです。
DVWAの構築では、2つの点でつまずきました。
一つは、公式のcompose定義ファイルの名前です。
DVWAはDocker Composeの慣例に従って、ファイル名をdocker-compose.ymlではなくcompose.ymlにしています。
docker-compose.ymlという名前で探しても見つからず、GitHub上のファイル一覧を確認して初めてcompose.ymlという名前だと気づきました。
もう一つは、データベースの初期化です。
起動後、http://localhost:4280/setup.phpにアクセスして「Create / Reset Database」ボタンを押すとDBが初期化される仕組みなのですが、このフォームにはCSRFトークンが必要で、curlで一括自動化しようとするとエラーになってしまいました。
無理に自動化せず、ブラウザで一度ボタンを押す手順として運用することにしました。
初期化後はadmin/passwordでログインできます。
公式リポジトリ: https://github.com/digininja/DVWA
OWASP crAPI
crAPI(completely ridiculous API)は、OWASP製で現役でメンテナンスが続いているAPIセキュリティ学習アプリです。
BOLA(IDOR)、JWT改ざん、マスアサインメントなど、OWASP API Security Top 10に沿った脆弱性を、実際のAPIリクエストを通して学べます。
crAPIは中古車販売サイトという設定になっていて、上の画像はログイン後に表示される車両詳細ページです。
ここに登場するAPIエンドポイントの一つひとつに、BOLAをはじめとする脆弱性が仕込まれています。
crAPIは他の3つと違い、Identity、Community、Workshop、Chatbot、Web、Gatewayの各サービスに加えて、PostgreSQL、MongoDB、ChromaDB、MailHogまで含む10コンテナのマイクロサービス構成になっています。
公式が改変不要の完全なcompose定義を配布しているので、そのまま取得して使います。
curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/OWASP/crAPI/main/deploy/docker/docker-compose.yml
curl -fsSL -o .env https://raw.githubusercontent.com/OWASP/crAPI/main/deploy/docker/.env
mkdir -p keys
curl -fsSL -o keys/jwks.json https://raw.githubusercontent.com/OWASP/crAPI/main/deploy/docker/keys/jwks.json
docker compose --compatibility up -d
http://localhost:8888が本体、http://localhost:8025はMailHog(送信されたメールを確認するためのUI)になっています。
crAPIの構築では、サービス数の多さに起因する点でいくつか気をつける必要がありました。
pullだけでもそれなりに時間がかかるので、先にバックグラウンドで済ませておくとよさそうです。
起動コマンドに--compatibilityオプションが必要な点も他の3つとは異なります(各サービスのCPU/メモリ制限がdeploy.resourcesで定義されており、これを単体のDocker Compose環境でも有効にするために公式手順で指定されています)。
crapi-identityサービスはJWT鍵(keys/jwks.json)のマウントを必要とするので、上記のように事前に取得しておきます。
公式リポジトリ: https://github.com/OWASP/crAPI
これらを自動化するClaude Code Skillを作りました
4つの環境を構築し終えて、毎回同じdocker-composeの手順を思い出しながら打つのが手間になってきました。
環境を作っては壊し、また作り直すというサイクルを何度も繰り返すことも多かったので、この一連の操作をClaude Code向けのSkillとしてまとめてみました。
Skill名はsecurity-labで、次の6つのアクションを持ちます。
-
setup:docker-compose定義を生成する(起動はしない) -
build:setupを実行してから、最新イメージをpullして起動する -
up:既存の状態のまま起動する -
stop:コンテナを止める(データは保持される) -
reset:コンテナとボリュームを削除してから作り直す -
check:起動や停止の操作はせず、稼働中か停止中かだけを確認する
環境名(juice-shop/webgoat/dvwa/crapi、まとめてallも指定できます)とアクションを組み合わせて呼び出します。
/security-lab dvwa reset
/security-lab all check
Skill本体はSKILL.md1枚だけを持ち、setupアクションの実行時にその場でcompose定義を生成する(またはcrAPIのように公式リポジトリが完全な定義を配布している場合はそこから直接取得する)ようになっています。
Dockerさえ入っていれば、どのマシンのどのプロジェクトからでもそのまま動くはずです。
リポジトリ: https://github.com/fuchiuebusi-lab/securiy-lab-claude-skill
インストールは、リポジトリをクローンしてsecurity-labディレクトリを~/.claude/skills/(全プロジェクトで使う場合)か、特定プロジェクトの.claude/skills/にコピーするだけです。
他にどんなツールがあるか調べる方法
今回は4つに絞りましたが、この種の学習用アプリケーションは他にも数多く存在します。
網羅的に探したいときは、OWASPが管理している**Vulnerable Web Applications Directory(VWAD)**の利用をお勧めします。
VWADは、脆弱性学習用アプリケーションをOnline、Offline、Mobile、Containerized、Platformといった提供形態ごとに分類した公式カタログで、新しいツールが週単位で追加されています。
GitHub上にもawesome-vulnerable-appsのようなまとめリストがあるので、あわせて確認すると選択肢が広がると思います。
ブラウザだけでできる学習サイトもある
Dockerの環境構築自体がハードルになる場合や、今すぐ手を動かしたい場合には、ブラウザだけで完結する学習サイトも選択肢になります。
PortSwigger Web Security Academyは、Burp Suiteの開発元であるPortSwiggerが提供する無料のオンライン学習サイトです。
SQLインジェクション、あらゆる種類のXSS、CSRF、SSRF、GraphQL、HTTPリクエストスマグリングまで、250以上のハンズオンラボがブラウザ上で完結します。
ローカル環境の構築が不要なので、まず何かを試してみたいというときに向いています。
まとめ
Juice Shop、WebGoat、DVWA、crAPIの4つをDockerで構築し、それぞれの特徴とつまずいた点を紹介しました。
この4つはあくまで数ある選択肢の一部で、VWADのような一次情報源を辿れば他の環境も見つかります。
Docker環境を構築する余裕がなければ、PortSwigger Web Security Academyのようなブラウザ完結型のサイトから始めてみるのもよさそうです。
今回作った構築手順は、Claude Code向けのSkillとしてまとめてあります。
Dockerが入っている環境であれば、このSkillをコピーするだけで同じ4つの学習環境をすぐに再現できます。



