APIログの種類と目的
APIのログには主に以下の種類があります:
- アクセスログ:誰がいつどのAPIを呼んだかの記録
- 監査ログ:重要な操作(データ変更・権限変更・設定変更)の記録
- エラーログ:エラー・例外の記録
- パフォーマンスログ:レスポンスタイム・スループットの記録
構造化ログの実装(Node.js)
import winston from 'winston';
// 構造化ログの設定
const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'access.log' })
]
});
// APIアクセスログミドルウェア
const accessLogger = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info('api_access', {
timestamp: new Date().toISOString(),
method: req.method,
path: req.path,
query: req.query,
status: res.statusCode,
duration_ms: duration,
user_id: req.user?.id || null,
client_ip: req.headers['x-forwarded-for']?.split(',')[0] || req.ip,
user_agent: req.headers['user-agent'],
request_id: req.headers['x-request-id'] || req.id,
api_key_id: req.apiKey?.id || null
});
});
next();
};
監査ログの実装(重要操作の記録)
// 重要な操作を監査ログに記録
const auditLog = async ({
userId,
action,
resourceType,
resourceId,
oldValue,
newValue,
ipAddress,
result
}) => {
await db.auditLogs.create({
data: {
userId,
action, // 'USER_ROLE_UPDATE', 'PAYMENT_CREATED', etc.
resourceType, // 'User', 'Order', 'Product', etc.
resourceId,
oldValue: JSON.stringify(oldValue), // 変更前の値
newValue: JSON.stringify(newValue), // 変更後の値
ipAddress,
result, // 'success' | 'failure'
timestamp: new Date()
}
});
};
// ユーザーロール変更時
app.put('/api/users/:id/role', authenticate, authorize('admin'), async (req, res) => {
const oldUser = await db.users.findUnique({ where: { id: req.params.id } });
const updated = await db.users.update({
where: { id: req.params.id },
data: { role: req.body.role }
});
await auditLog({
userId: req.user.id,
action: 'USER_ROLE_UPDATE',
resourceType: 'User',
resourceId: req.params.id,
oldValue: { role: oldUser.role },
newValue: { role: req.body.role },
ipAddress: req.ip,
result: 'success'
});
res.json(updated);
});
ログの集中管理(ELKスタック)
// Logstashへのログ転送設定(Winstonのlogstash transport)
import Logstash from 'winston-logstash-transport';
logger.add(new Logstash({
host: process.env.LOGSTASH_HOST,
port: 5044,
ssl_enable: true
}));
// ElasticsearchへのAPIアクセスログの転送で
// Kibanaでリアルタイムダッシュボードと異常検知を実現
異常アクセス検知のルール例
- 同一IPから5分間に1000回以上のリクエスト → ブルートフォース攻撃の可能性
- 認証失敗が連続10回 → アカウント攻撃の可能性
- 深夜の管理APIアクセス → 不審なアクセス
- 短時間での大量データエクスポート → データ窃取の可能性
- 普段とは異なる国からのアクセス → アカウント侵害の可能性
まとめ
APIの監査ログは不正アクセスの検知・コンプライアンス対応・インシデント調査に不可欠です。構造化ログ(JSON形式)を採用し、ELKスタックやAWS CloudWatchに集中管理することで、異常検知・アラート・ログ分析が可能になります。個人情報・機密情報をログに含めないよう設計し、適切な保存期間を設定してください。