はじめに
Webアプリケーションのセキュリティを学ぶために、意図的に100以上の脆弱性を埋め込んだ学習用アプリケーションを作成しました。この記事では、その開発過程と学んだことを共有します。
IBM Bobを活用した開発
このプロジェクトは、IBM Bobの対話型AIアシスタントを使って、すべての実装を行いました。
IBM Bobで実現できたこと:
- ✅ フルスタック開発: React 18フロントエンド + Node.js/Expressバックエンドの完全実装
- ✅ Docker環境構築: 5つのコンテナ(frontend, backend, PostgreSQL, MongoDB, Adminer)の設定
- ✅ 100以上の脆弱性の埋め込み: OWASP Top 10に基づく体系的な脆弱性実装
- ✅ トラブルシューティング: bcryptのネイティブモジュールエラー、CORS設定、データフェッチングの問題解決
- ✅ 包括的なドキュメント作成: README、VULNERABILITIES.md、この記事の作成
- ✅ Git/GitHub統合: リポジトリ初期化、コミット、プッシュまで完全自動化
IBM Bobの強み:
- 広範囲な技術知識: フロントエンド、バックエンド、データベース、Docker、セキュリティなど、複数の技術領域を横断的にサポート
- 段階的な実装: 複雑なプロジェクトを適切なステップに分解し、一つずつ確実に実装
- 問題解決能力: エラーが発生した際、原因を分析し、適切な解決策を提示
- ベストプラクティスの提案: セキュリティ、コーディング規約、プロジェクト構造など、業界標準に沿った実装
このようなWeb開発の学習プロジェクトにも、IBM Bobは非常に有効なツールです。特に、セキュリティのような専門的な知識が必要な分野では、AIアシスタントの支援が大きな助けとなります。
⚠️ 重要な注意事項
この記事で紹介するコードには意図的にセキュリティ脆弱性が含まれています。教育目的のみで使用し、本番環境では絶対に使用しないでください。
🎯 プロジェクトの目的
- OWASP Top 10の脆弱性を実践的に学ぶ
- ペネトレーションテストの練習環境を構築
- セキュアコーディングのベストプラクティスを理解する
🛠️ 技術スタック
- フロントエンド: React 18
- バックエンド: Node.js + Express
- データベース: PostgreSQL + MongoDB
- コンテナ: Docker + Docker Compose
- テストツール: OWASP ZAP, Burp Suite, SQLMap
📁 プロジェクト構造
security-learning-project/
├── vulnerable-app/ # 脆弱なアプリケーション
│ ├── backend/ # Node.js API
│ ├── frontend/ # React SPA
│ └── docker-compose.yml # 環境構築
├── VULNERABILITIES.md # 脆弱性リスト
└── README.md
🚀 環境構築
Docker Composeで一発起動
cd vulnerable-app
docker-compose up -d
これだけで以下のサービスが起動します:
- フロントエンド: http://localhost:3001
- バックエンドAPI: http://localhost:3000
- PostgreSQL: localhost:5432
- MongoDB: localhost:27017
- Adminer (DB管理): http://localhost:8080
🔐 埋め込んだ脆弱性(一部紹介)
1. SQLインジェクション
脆弱なコード例:
// backend/src/routes/auth.js
router.post('/login', async (req, res) => {
const { username, password } = req.body;
// ❌ ユーザー入力を直接SQLに埋め込み
const query = `SELECT * FROM users WHERE username = '${username}'`;
const result = await executeRawQuery(query);
// ...
});
攻撃例:
ユーザー名: admin' OR '1'='1
パスワード: anything
これで認証をバイパスしてログインできてしまいます。
正しい実装:
// ✅ パラメータ化クエリを使用
const query = 'SELECT * FROM users WHERE username = $1';
const result = await pool.query(query, [username]);
2. XSS(クロスサイトスクリプティング)
脆弱なコード例:
// frontend/src/components/Home.js
<div
className="post-content"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
攻撃例:
投稿内容に以下を入力:
<script>alert('XSS Attack!')</script>
正しい実装:
// ✅ HTMLをエスケープして表示
<div className="post-content">
{post.content}
</div>
3. 認証なしのパスワードリセット
脆弱なコード例:
// backend/src/routes/auth.js
router.post('/reset-password', async (req, res) => {
const { username, newPassword } = req.body;
// ❌ 認証チェックなし!
const hashedPassword = await bcrypt.hash(newPassword, 10);
const query = `UPDATE users SET password = '${hashedPassword}' WHERE username = '${username}'`;
await executeRawQuery(query);
res.json({ message: 'Password reset successfully' });
});
誰でも他人のパスワードを変更できてしまいます。
正しい実装:
// ✅ メール確認とトークン検証を実装
router.post('/reset-password', verifyResetToken, async (req, res) => {
// トークンの検証後にパスワード変更
});
4. 権限昇格の脆弱性
脆弱なコード例:
// backend/src/routes/auth.js
router.post('/register', async (req, res) => {
const { username, email, password, role } = req.body;
// ❌ ユーザーが自分でroleを指定できる
const userRole = role || 'user';
const query = `INSERT INTO users (username, email, password, role)
VALUES ('${username}', '${email}', '${hashedPassword}', '${userRole}')`;
});
攻撃例:
登録時にブラウザの開発者ツールで以下を送信:
{
"username": "hacker",
"email": "hacker@example.com",
"password": "test123",
"role": "admin"
}
正しい実装:
// ✅ roleはサーバー側で固定
const userRole = 'user'; // クライアントからの入力を無視
5. 機密情報の露出
脆弱なコード例:
// backend/src/server.js
app.get('/health', (req, res) => {
res.json({
database: {
password: process.env.DB_PASSWORD // ❌ パスワードを露出
},
secrets: {
jwtSecret: process.env.JWT_SECRET // ❌ JWT秘密鍵を露出
}
});
});
正しい実装:
// ✅ 機密情報を含めない
app.get('/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString()
});
});
📊 埋め込んだ脆弱性の統計
OWASP Top 10 (2021) 分類
| カテゴリ | 脆弱性数 |
|---|---|
| A01: Broken Access Control | 15 |
| A02: Cryptographic Failures | 18 |
| A03: Injection | 20 |
| A04: Insecure Design | 8 |
| A05: Security Misconfiguration | 12 |
| A07: Identification and Authentication Failures | 14 |
| A09: Security Logging and Monitoring Failures | 13 |
合計: 100以上の脆弱性
深刻度別
| 深刻度 | 脆弱性数 |
|---|---|
| Critical | 25 |
| High | 35 |
| Medium | 30 |
| Low | 10+ |
🧪 実際に試してみる
1. SQLインジェクションでログイン
ユーザー名: admin' OR '1'='1
パスワード: (何でもOK)
2. XSS攻撃
新規投稿で以下を入力:
<script>alert(document.cookie)</script>
3. 権限昇格
ユーザー登録時に開発者ツールのNetworkタブでリクエストを確認し、role: "admin"を追加。
🔍 開発中に遭遇した問題と解決策
問題1: Docker内でbcryptがクラッシュ
エラー:
Error: /app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node:
Exec format error
原因:
ローカルのnode_modules(macOS ARM64用)がDockerコンテナ(Linux ARM64)にマウントされ、バイナリの互換性がなかった。
解決策:
# docker-compose.yml
volumes:
# ❌ これだとnode_modulesもマウントされる
# - ./backend:/app
# ✅ 必要なファイルだけマウント
- ./backend/src:/app/src
- ./backend/package.json:/app/package.json
問題2: CORSエラー
エラー:
Access to XMLHttpRequest has been blocked by CORS policy:
Request header field x-api-key is not allowed
解決策:
// server.js
app.use(cors({
origin: '*',
allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key']
}));
問題3: フロントエンドでのデータ取得エラー
エラー:
TypeError: posts.map is not a function
原因:
バックエンドAPIが{posts: [...]} という形式で返していたが、フロントエンドは配列を期待していた。
解決策:
// Home.js
const loadPosts = async () => {
const data = await postAPI.getPosts();
// APIレスポンスの形式に対応
const postsArray = data.posts || data;
setPosts(Array.isArray(postsArray) ? postsArray : []);
};
📚 学んだこと
1. セキュリティは多層防御が重要
一つの対策だけでは不十分。以下のような多層的なアプローチが必要:
- 入力検証: クライアント側とサーバー側の両方で
- 出力エスケープ: XSS対策
- パラメータ化クエリ: SQLインジェクション対策
- 認証・認可: すべてのエンドポイントで
- セキュリティヘッダー: CSP、HSTS、X-Frame-Optionsなど
2. 「デフォルトで安全」な設計
- パスワードは必ずハッシュ化
- セッションはHTTPOnlyとSecure属性を有効に
- CORSは必要最小限のオリジンのみ許可
- エラーメッセージは詳細を含めない
3. 開発者ツールは攻撃者のツールでもある
ブラウザの開発者ツールで以下が可能:
- リクエストの改ざん
- localStorageの閲覧・編集
- JavaScriptの実行
クライアント側の検証だけでは不十分で、サーバー側での検証が必須。
4. ログとモニタリングの重要性
攻撃を検知するには:
- 適切なログ記録
- 異常なアクセスパターンの検出
- セキュリティイベントのアラート
ただし、ログに機密情報を含めないよう注意。
🎓 このプロジェクトを使った次のステップ(推奨)
-
ペネトレーションテスト
- OWASP ZAPでの自動スキャン
- Burp Suiteでの手動テスト
- SQLMapでのSQLインジェクション検証
-
セキュアなアプリケーションの実装
- すべての脆弱性を修正
- ベストプラクティスの適用
- セキュリティテストの自動化
-
CI/CD統合
- セキュリティスキャンの自動化
- 脆弱性検出時のビルド失敗
📖 参考資料
- OWASP Top 10 2021
- OWASP Testing Guide
- CWE Top 25
- 「体系的に学ぶ 安全なWebアプリケーションの作り方」徳丸浩
🔗 リポジトリ
完全なソースコードとドキュメントはGitHubで公開しています:
GitHub: https://github.com/mnori0211/security-learning-project
リポジトリには以下が含まれています:
- 完全なソースコード(フロントエンド + バックエンド)
- Docker環境設定
- 100以上の脆弱性の詳細リスト(VULNERABILITIES.md)
- セットアップガイド(README.md)
このプロジェクトは教育目的で作成されています。実際のアプリケーション開発では、これらの脆弱性を絶対に含めないでください。
まとめ
脆弱なアプリケーションを意図的に作ることで、以下を学べました:
- ✅ 一般的なセキュリティ脆弱性の実装と悪用方法
- ✅ 攻撃者の視点でのシステム評価
- ✅ セキュアコーディングのベストプラクティス
- ✅ Docker環境でのトラブルシューティング
セキュリティは一度学んで終わりではなく、継続的な学習が必要です。このプロジェクトを通じて、実践的なセキュリティスキルを身につけることができました。
皆さんもぜひ、安全な環境でセキュリティテストを試してみてください!