APIに特化した最も重要な10のセキュリティリスクと、その対策方法を解説します。
OWASP(Open Worldwide Application Security Project)が公開するAPI固有のセキュリティリスクランキングです。2023年版では、APIの普及に伴い増加する脅威を反映した最新のリストが提供されています。
オブジェクトIDを操作することで、他のユーザーのデータに不正アクセスできる脆弱性です。最も頻出かつ悪用が容易な脆弱性として知られています。
攻撃者はURLやリクエストパラメータのIDを変更するだけで、他ユーザーの個人情報・決済情報・注文履歴などにアクセスできてしまいます。
// IDを受け取ってそのまま返す - 認可チェックなし app.get('/api/users/:id/orders', async (req, res) => { const orders = await Order.find({ userId: req.params.id }); res.json(orders); });
// 認証済みユーザーのIDと照合して認可チェック app.get('/api/users/:id/orders', authenticate, async (req, res) => { if (req.user.id !== req.params.id && !req.user.isAdmin) { return res.status(403).json({ error: 'Forbidden' }); } const orders = await Order.find({ userId: req.params.id }); res.json(orders); });
認証メカニズムの実装ミスにより、攻撃者が正規ユーザーのアカウントを乗っ取れてしまう脆弱性です。
弱いパスワードポリシー、トークンの不適切な管理、ブルートフォース対策の欠如、セッション管理の不備など。
const jwt = require('jsonwebtoken'); function authenticate(req, res, next) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Token required' }); try { // アルゴリズムを明示的に指定(alg: none 攻撃を防止) const decoded = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'], issuer: 'your-app', }); req.user = decoded; next(); } catch (err) { res.status(401).json({ error: 'Invalid token' }); } }
APIレスポンスに含まれるオブジェクトのプロパティ(フィールド)に対するアクセス制御が不十分な脆弱性です。過剰なデータ露出(Excessive Data Exposure)とマスアサインメント(Mass Assignment)を統合した項目です。
// ユーザーオブジェクトから公開フィールドのみ返す function sanitizeUser(user, requesterId) { const publicFields = { id: user.id, name: user.name, avatar: user.avatar }; // 本人のみ追加フィールドを見れる if (requesterId === user.id) { publicFields.email = user.email; publicFields.phone = user.phone; } return publicFields; // ❌ return user; とすると password_hash 等も漏洩する }
APIリクエストのサイズ・頻度・リソース消費に制限がなく、DoS攻撃やコストの急騰を引き起こす脆弱性です。
const rateLimit = require('express-rate-limit'); // グローバルレート制限 app.use(rateLimit({ windowMs: 15 * 60 * 1000, // 15分 max: 100, // 最大100リクエスト standardHeaders: true, })); // ペイロードサイズ制限 app.use(express.json({ limit: '10kb' })); // ページネーション上限 app.get('/api/items', (req, res) => { const limit = Math.min(parseInt(req.query.limit) || 20, 100); // ... });
管理者向け機能やエンドポイントに対する適切なアクセス制御が実装されておらず、一般ユーザーが管理操作を実行できてしまう脆弱性です。
function authorize(...roles) { return (req, res, next) => { if (!roles.includes(req.user.role)) { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); }; } // 管理者のみアクセス可能 app.delete('/api/admin/users/:id', authenticate, authorize('admin'), deleteUser); // 管理者とモデレーター app.put('/api/posts/:id/moderate', authenticate, authorize('admin', 'moderator'), moderatePost);
ビジネスロジック上の重要なフローが自動化攻撃から保護されていない脆弱性です。例: チケットの買い占め、クーポンの大量取得、スパム投稿など。
ユーザー提供のURLをサーバーが検証なしにフェッチすることで、内部ネットワークへの不正アクセスが可能になる脆弱性です。
const { URL } = require('url'); function isAllowedUrl(input) { try { const url = new URL(input); // プロトコル制限 if (!['https:', 'http:'].includes(url.protocol)) return false; // プライベートIP範囲をブロック const blocked = ['127.0.0.1', 'localhost', '0.0.0.0', '169.254.169.254']; if (blocked.includes(url.hostname)) return false; // 内部ネットワーク範囲チェック(10.x, 172.16-31.x, 192.168.x) if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(url.hostname)) return false; return true; } catch { return false; } }
APIサーバーやフレームワークのセキュリティ設定が不適切な状態。不要なHTTPメソッドの許可、CORSの過度な緩和、デバッグ情報の露出など。
const helmet = require('helmet'); const cors = require('cors'); app.use(helmet()); app.use(cors({ origin: ['https://app.example.com'], // ワイルドカードは使わない methods: ['GET', 'POST', 'PUT', 'DELETE'], credentials: true, })); // エラーハンドラ: 本番環境ではスタックトレースを返さない app.use((err, req, res, next) => { res.status(500).json({ error: process.env.NODE_ENV === 'production' ? 'Internal Server Error' : err.message, }); });
古いバージョンのAPIエンドポイントが放置され、セキュリティパッチが適用されないまま公開されている状態。シャドウAPIやゾンビAPIとも呼ばれます。
サードパーティAPIからのレスポンスを検証せずに信頼してしまう脆弱性。外部APIが侵害された場合、自システムにも影響が波及します。
const Ajv = require('ajv'); const ajv = new Ajv(); // 外部APIのレスポンスをスキーマで検証 const externalSchema = { type: 'object', required: ['id', 'status'], properties: { id: { type: 'string', maxLength: 50 }, status: { type: 'string', enum: ['active', 'inactive'] }, }, additionalProperties: false, }; const validate = ajv.compile(externalSchema); async function fetchExternalData() { const res = await fetch('https://api.external.com/data'); const data = await res.json(); if (!validate(data)) { throw new Error('External API response validation failed'); } return data; }
| ID | 脆弱性 | 重要度 | 主な対策 |
|---|---|---|---|
| API1 | Broken Object Level Authorization | Critical | オブジェクトレベルの認可チェック |
| API2 | Broken Authentication | Critical | 適切なトークン管理・ブルートフォース対策 |
| API3 | Broken Object Property Level Authorization | High | レスポンスフィールドの明示的フィルタリング |
| API4 | Unrestricted Resource Consumption | High | レート制限・ペイロードサイズ制限 |
| API5 | Broken Function Level Authorization | High | ロールベースのアクセス制御 |
| API6 | Unrestricted Access to Sensitive Business Flows | Medium | CAPTCHA・ビジネスレベルの制限 |
| API7 | Server Side Request Forgery | High | URL検証・プライベートIPブロック |
| API8 | Security Misconfiguration | Medium | セキュリティヘッダー・CORS設定 |
| API9 | Improper Inventory Management | Medium | APIインベントリ管理・廃止ポリシー |
| API10 | Unsafe Consumption of APIs | Medium | 外部APIレスポンスのスキーマ検証 |