- Published on
アプリケーションセキュリティエンジニアリングガイド — OWASP Top 10、認証、暗号化、DevSecOps
- Authors

- Name
- Youngju Kim
- @fjvbn20031
アプリケーションセキュリティエンジニアリングガイド
ソフトウェアがビジネスの中核となった時代、セキュリティは選択ではなく生存の問題です。このガイドはOWASP Top 10からDevSecOpsパイプラインまで、アプリケーションセキュリティの全範囲をカバーします。
1. なぜセキュリティが重要なのか
データ漏洩の現実
IBMの「Cost of a Data Breach Report」によると、2024年時点でデータ漏洩1件あたりの平均コストは約488万ドルに達しています。漏洩事故の主な原因は以下の通りです。
| 原因 | 割合 | 平均コスト |
|---|---|---|
| フィッシング攻撃 | 16% | 476万ドル |
| 盗難/漏洩した認証情報 | 15% | 463万ドル |
| クラウド設定ミス | 12% | 414万ドル |
| ゼロデイ脆弱性 | 10% | 518万ドル |
開発者のセキュリティ責任
セキュリティはもはやセキュリティチームだけの責任ではありません。「Shift Left」パラダイムに従い、開発の初期段階からセキュリティを組み込む必要があります。
- コーディング段階での脆弱性防止は、デプロイ後のパッチ適用より6〜100倍安価です
- SDLC(ソフトウェア開発ライフサイクル)全体を通じてセキュリティを考慮する必要があります
- セキュリティは機能(feature)ではなく、品質(quality)の一部です
CIAトライアド
- Confidentiality(機密性): 認可されたユーザーのみがデータにアクセスできる
- Integrity(完全性): データが無断で改ざんされていないことを保証する
- Availability(可用性): 必要な時にシステムとデータにアクセスできる
2. OWASP Top 10 (2021)
OWASP Top 10は、Webアプリケーションにおける最も深刻な10のセキュリティ脆弱性をまとめたものです。各脆弱性とその防御策を見ていきましょう。
A01: Broken Access Control(アクセス制御の不備)
最も一般的な脆弱性です。認可されていないユーザーが他のユーザーのデータにアクセスしたり、管理者機能を実行できてしまいます。
攻撃シナリオ: URLパラメータを変更して他のユーザーの注文履歴を閲覧
防御策:
# Flaskでのアクセス制御デコレータ
from functools import wraps
from flask import abort, g
def require_role(role):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not g.current_user or g.current_user.role != role:
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
@app.route('/admin/users')
@require_role('admin')
def admin_users():
return get_all_users()
- デフォルトですべてのアクセスを拒否し、ホワイトリスト方式で明示的に許可します
- サーバーサイドで必ず権限を検証します
- IDOR(安全でない直接オブジェクト参照)防止のためUUIDを使用します
A02: Cryptographic Failures(暗号化の失敗)
機密データが平文で送信されたり、弱い暗号化で保護されている場合です。
防御策:
- 転送中のデータ: TLS 1.3を使用
- 保存データ: AES-256-GCMで暗号化
- パスワード: bcryptまたはArgon2でハッシュ化
- MD5やSHA-1のような脆弱なアルゴリズムを使用しない
A03: Injection(インジェクション)
SQL、NoSQL、OSコマンド、LDAPなどのインジェクション攻撃です。
脆弱なコード:
# 絶対にこうしてはいけません - SQLインジェクションに脆弱
query = "SELECT * FROM users WHERE id = " + user_input
安全なコード:
# パラメータ化クエリを使用
cursor.execute("SELECT * FROM users WHERE id = %s", (user_input,))
# ORMを使用 (SQLAlchemy)
user = User.query.filter_by(id=user_input).first()
A04: Insecure Design(安全でない設計)
設計段階でのセキュリティ上の欠陥です。コードレベルではなくアーキテクチャレベルの問題です。
防御策:
- 脅威モデリングの実施(STRIDE、PASTA手法)
- セキュア設計原則の適用(最小権限、多層防御、フェイルセキュア)
- ビジネスロジックに対するセキュリティシナリオテスト
A05: Security Misconfiguration(セキュリティ設定ミス)
デフォルトアカウントの未変更、不要な機能の有効化、本番環境でのデバッグモード公開などが該当します。
チェックリスト:
- デフォルトパスワードを変更したか
- 不要なポートとサービスを無効化したか
- エラーメッセージにスタックトレースが公開されていないか
- セキュリティヘッダー(X-Frame-Options、X-Content-Type-Options)が設定されているか
A06: Vulnerable and Outdated Components(脆弱で古いコンポーネント)
既知の脆弱性があるライブラリやフレームワークを使用している場合です。
防御策:
# npmセキュリティ監査
npm audit
# Python依存関係の検査
pip-audit
# Go脆弱性チェック
govulncheck ./...
A07: Identification and Authentication Failures(認証の失敗)
弱いパスワードポリシー、不十分なセッション管理、ブルートフォース攻撃の放置などが該当します。詳細は第3章で扱います。
A08: Software and Data Integrity Failures(ソフトウェアとデータの整合性の失敗)
CI/CDパイプライン、ソフトウェアアップデート、シリアル化における整合性検証の不足です。
防御策:
- デジタル署名によるソフトウェアの整合性検証
- SBOM(ソフトウェア部品表)の管理
- CI/CDパイプラインのセキュリティ確保(コード署名、アクセス制御)
A09: Security Logging and Monitoring Failures(ロギングとモニタリングの失敗)
セキュリティイベントを記録していない、または記録していてもモニタリングしていない場合です。
必須ログ項目:
import logging
import json
from datetime import datetime, timezone
security_logger = logging.getLogger('security')
def log_security_event(event_type, user_id, details):
event = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"event_type": event_type,
"user_id": user_id,
"ip_address": request.remote_addr,
"user_agent": request.headers.get('User-Agent'),
"details": details
}
security_logger.warning(json.dumps(event))
# 使用例
log_security_event("LOGIN_FAILED", "user123", "Invalid password attempt 3")
log_security_event("PRIVILEGE_ESCALATION", "user456", "Attempted admin access")
A10: Server-Side Request Forgery (SSRF)
サーバーが攻撃者の指定したURLにリクエストを送信するよう誘導する攻撃です。
防御策:
- 許可されたURLのホワイトリストを適用
- 内部ネットワークIP帯(10.x、172.16.x、192.168.x)へのリクエストをブロック
- DNS Rebinding攻撃への対策
3. 認証(Authentication)
認証は、ユーザーが主張する本人であることを確認するプロセスです。
パスワードハッシュ化
パスワードは絶対に平文や可逆暗号化で保存してはいけません。
# Argon2 - 現在最も推奨されるハッシュアルゴリズム
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=3, # 繰り返し回数
memory_cost=65536, # 64MBメモリ
parallelism=4, # 並列スレッド数
hash_len=32, # ハッシュ長
salt_len=16 # ソルト長
)
# ハッシュ化
hashed = ph.hash("user_password")
# 出力例: $argon2id$v=19$m=65536,t=3,p=4$...
# 検証
try:
ph.verify(hashed, "user_password")
print("パスワード一致")
except Exception:
print("パスワード不一致")
# bcrypt - 広く使用されている代替手段
import bcrypt
password = b"user_password"
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(password, salt)
# 検証
if bcrypt.checkpw(password, hashed):
print("パスワード一致")
多要素認証(MFA)
パスワードだけでは不十分です。少なくとも2つの認証要素を組み合わせます。
| 認証要素 | 説明 | 例 |
|---|---|---|
| 知識(Something you know) | ユーザーが知っている情報 | パスワード、PIN |
| 所有(Something you have) | ユーザーが持っている物 | スマートフォン、セキュリティキー |
| 生体(Something you are) | ユーザーの身体的特徴 | 指紋、顔認証 |
# TOTP(時間ベースのワンタイムパスワード)実装
import pyotp
# 秘密鍵の生成
secret = pyotp.random_base32()
# QRコードURI生成
totp_uri = pyotp.totp.TOTP(secret).provisioning_uri(
name="user@example.com",
issuer_name="MyApp"
)
# 検証
totp = pyotp.TOTP(secret)
is_valid = totp.verify("123456") # ユーザー入力コード
パスキー(WebAuthn/FIDO2)
パスワード不要の未来のための認証標準です。
- 公開鍵暗号ベースでフィッシングに強い
- 生体認証またはPINによるローカル認証後、サーバーには公開鍵のみ送信
- Apple、Google、Microsoftすべてがサポート
// パスキー登録(ブラウザ側)
const credential = await navigator.credentials.create({
publicKey: {
challenge: serverChallenge,
rp: { name: "MyApp", id: "myapp.com" },
user: {
id: userId,
name: "user@example.com",
displayName: "ユーザー"
},
pubKeyCredParams: [
{ alg: -7, type: "public-key" }, // ES256
{ alg: -257, type: "public-key" } // RS256
],
authenticatorSelection: {
authenticatorAttachment: "platform",
residentKey: "required",
userVerification: "required"
}
}
});
4. 認可(Authorization)
認可は、認証されたユーザーがどのリソースにアクセスできるかを決定するプロセスです。
RBAC(ロールベースアクセス制御)
最も広く使用される認可モデルです。ユーザーにロールを割り当て、ロールに権限をマッピングします。
# RBAC実装例
PERMISSIONS = {
"admin": ["read", "write", "delete", "manage_users"],
"editor": ["read", "write"],
"viewer": ["read"],
}
def check_permission(user_role, required_permission):
role_permissions = PERMISSIONS.get(user_role, [])
return required_permission in role_permissions
# 使用
if check_permission(current_user.role, "delete"):
delete_resource(resource_id)
else:
raise PermissionError("削除権限がありません")
ABAC(属性ベースアクセス制御)
ユーザー属性、リソース属性、環境属性に基づいてきめ細かなアクセス制御を行います。
# ABACポリシー例
def evaluate_policy(user, resource, action, environment):
# 勤務時間内のみアクセスを許可
if environment["hour"] < 9 or environment["hour"] > 18:
return False
# 同じ部署のドキュメントのみアクセス可能
if user["department"] != resource["department"]:
return False
# マネージャーは全操作可能、一般社員は読み取りのみ
if action == "write" and user["level"] < 3:
return False
return True
OAuth 2.0 スコープ
OAuth 2.0において、スコープはクライアントがアクセスできるリソースの範囲を制限します。
# OAuth 2.0 スコープ定義例
scopes:
read:profile: "ユーザープロフィールの読み取り"
write:profile: "ユーザープロフィールの更新"
read:orders: "注文履歴の閲覧"
admin:users: "ユーザー管理(管理者専用)"
JWTセキュリティのベストプラクティス
JWTは便利ですが、誤った使い方をすると深刻なセキュリティ問題が発生します。
import jwt
from datetime import datetime, timedelta, timezone
# JWT作成(RS256推奨)
def create_token(user_id, role):
payload = {
"sub": user_id,
"role": role,
"iat": datetime.now(timezone.utc),
"exp": datetime.now(timezone.utc) + timedelta(minutes=15),
"iss": "myapp.com",
"aud": "myapp.com"
}
return jwt.encode(payload, PRIVATE_KEY, algorithm="RS256")
# JWT検証
def verify_token(token):
try:
payload = jwt.decode(
token,
PUBLIC_KEY,
algorithms=["RS256"], # アルゴリズムを明示的に指定(none攻撃防止)
issuer="myapp.com",
audience="myapp.com"
)
return payload
except jwt.ExpiredSignatureError:
raise AuthError("トークンの有効期限が切れています")
except jwt.InvalidTokenError:
raise AuthError("無効なトークンです")
JWTセキュリティチェックリスト:
- HS256の代わりにRS256を使用(非対称署名)
- 有効期限(exp)を短く設定(15分以内)
- リフレッシュトークンはサーバーサイドで管理
- alg: none攻撃を防ぐためアルゴリズムを明示的に検証
5. 暗号化の実践
対称暗号化: AES-256-GCM
同じ鍵で暗号化と復号を行います。主にデータの保存時に使用されます。
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
# 鍵の生成(256ビット)
key = AESGCM.generate_key(bit_length=256)
# 暗号化
aesgcm = AESGCM(key)
nonce = os.urandom(12) # 96ビットノンス
plaintext = b"Sensitive data here"
aad = b"additional authenticated data" # 追加認証データ
ciphertext = aesgcm.encrypt(nonce, plaintext, aad)
# 復号
decrypted = aesgcm.decrypt(nonce, ciphertext, aad)
非対称暗号化: RSAとECDSA
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes, serialization
# ECDSA鍵ペアの生成
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()
# 署名
from cryptography.hazmat.primitives.asymmetric import utils
signature = private_key.sign(
b"message to sign",
ec.ECDSA(hashes.SHA256())
)
# 検証
public_key.verify(
signature,
b"message to sign",
ec.ECDSA(hashes.SHA256())
)
TLS設定のベストプラクティス
# Nginx TLS設定
server {
listen 443 ssl http2;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
# HSTSヘッダー
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
}
鍵管理とHSM
- 鍵をソースコードにハードコードしてはいけません
- AWS KMS、Google Cloud KMS、Azure Key Vaultなどのマネージドサービスを使用します
- HSM(Hardware Security Module)はハードウェア内部でのみ鍵を処理し、抽出を防止します
- 鍵ローテーションポリシーを策定し、自動化します
6. セキュアコーディング
入力バリデーション
すべての外部入力は信頼できません。
import re
from pydantic import BaseModel, validator, constr
class UserInput(BaseModel):
username: constr(min_length=3, max_length=30, pattern=r'^[a-zA-Z0-9_]+$')
email: str
age: int
@validator('email')
def validate_email(cls, v):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(pattern, v):
raise ValueError('無効なメール形式です')
return v
@validator('age')
def validate_age(cls, v):
if v < 0 or v > 150:
raise ValueError('無効な年齢です')
return v
出力エンコーディング(XSS防止)
# HTML出力時のエスケープ
from markupsafe import escape
user_input = '<script>alert("XSS")</script>'
safe_output = escape(user_input)
# 結果: <script>alert("XSS")</script>
パラメータ化クエリ
# SQLAlchemy ORMの使用
from sqlalchemy import text
# 安全な方法
result = db.session.execute(
text("SELECT * FROM users WHERE email = :email"),
{"email": user_email}
)
CORS設定
# Flask-CORS設定
from flask_cors import CORS
CORS(app, resources={
r"/api/*": {
"origins": ["https://myapp.com", "https://admin.myapp.com"],
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_headers": ["Content-Type", "Authorization"],
"max_age": 86400
}
})
CSP(Content Security Policy)
# CSPヘッダー設定
@app.after_request
def set_csp(response):
response.headers['Content-Security-Policy'] = (
"default-src 'self'; "
"script-src 'self' 'nonce-abc123'; "
"style-src 'self' 'unsafe-inline'; "
"img-src 'self' data: https:; "
"connect-src 'self' https://api.myapp.com; "
"frame-ancestors 'none'; "
"base-uri 'self'"
)
return response
7. APIセキュリティ
レート制限
# Flask-Limiterの使用
from flask_limiter import Limiter
limiter = Limiter(
app,
default_limits=["200 per day", "50 per hour"]
)
@app.route("/api/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
# ログインロジック
pass
@app.route("/api/data")
@limiter.limit("100 per hour")
def get_data():
# データ取得ロジック
pass
APIキー管理
- APIキーはヘッダーで渡します(URLパラメータには入れません)
- キーごとの権限範囲(スコープ)を制限します
- キーの発行/無効化の履歴を管理します
- 使用量を監視し、異常なパターンを検知します
mTLS(相互TLS認証)
サーバーとクライアントの双方が証明書を検証する方式です。
# Kubernetes IngressでのmTLS設定例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
spec:
tls:
- hosts:
- api.myapp.com
secretName: tls-secret
HMAC署名
リクエストの完全性と認証を同時に保証します。
import hmac
import hashlib
import time
def create_hmac_signature(secret_key, method, path, body, timestamp):
message = f"{method}\n{path}\n{timestamp}\n{body}"
signature = hmac.new(
secret_key.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return signature
# 検証(タイムスタンプチェック付き)
def verify_request(secret_key, method, path, body, timestamp, signature):
# 5分以内のリクエストのみ許可(リプレイ攻撃防止)
if abs(time.time() - float(timestamp)) > 300:
return False
expected = create_hmac_signature(secret_key, method, path, body, timestamp)
return hmac.compare_digest(expected, signature)
8. コンテナセキュリティ
イメージスキャン
# Trivyでコンテナイメージの脆弱性をスキャン
trivy image myapp:latest
# 重大度でフィルタリング
trivy image --severity HIGH,CRITICAL myapp:latest
# CI/CDで使用(脆弱性発見時にビルド失敗)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
最小権限Dockerfile
# マルチステージビルド
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# プロダクションイメージ
FROM node:20-alpine
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
WORKDIR /app
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
# root以外のユーザーで実行
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]
ルートレスコンテナ
- root権限なしでコンテナを実行します
- securityContextでrunAsNonRoot、readOnlyRootFilesystemを設定します
- 不要なLinux Capabilitiesを削除します
# Kubernetes Pod Security Context
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
OPA/Gatekeeper
Kubernetesクラスターのポリシーをコードとして管理します。
# 特権コンテナ拒否ポリシー
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: deny-privileged
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces:
- kube-system
9. DevSecOpsパイプライン
パイプラインの全体像
DevSecOpsは、開発(Dev)、セキュリティ(Sec)、運用(Ops)を統合するアプローチです。
| フェーズ | ツール | 目的 |
|---|---|---|
| コーディング | IDEセキュリティプラグイン | リアルタイム脆弱性検知 |
| コミット | Pre-commitフック | シークレット漏洩防止 |
| ビルド | SAST | 静的コード分析 |
| テスト | DAST | 動的セキュリティテスト |
| 依存関係 | SCA | サードパーティライブラリの脆弱性 |
| デプロイ | イメージスキャン | コンテナの脆弱性 |
| 運用 | RASP, WAF | ランタイムセキュリティ |
SAST(静的アプリケーションセキュリティテスト)
# GitHub ActionsでSonarQubeを実行
name: Security Scan
on: [push, pull_request]
jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: SONAR_TOKEN_PLACEHOLDER
SONAR_HOST_URL: SONAR_HOST_PLACEHOLDER
DAST(動的アプリケーションセキュリティテスト)
# OWASP ZAPを使用した動的セキュリティスキャン
docker run -t zaproxy/zap-stable zap-baseline.py \
-t https://myapp.com \
-r report.html
SCA(ソフトウェアコンポジション分析)
# Dependabot設定 (.github/dependabot.yml)
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
SBOM(ソフトウェア部品表)
# SyftでSBOMを生成
syft myapp:latest -o spdx-json > sbom.json
# GrypeでSBOMベースの脆弱性スキャン
grype sbom:sbom.json
Pre-commitでのシークレット検知
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
- repo: https://github.com/zricethezav/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
10. ペネトレーションテストの基礎
モデル化されたテスト手法
OWASP Testing Guideに基づくテストフェーズ:
- 情報収集(Reconnaissance): 対象システムの技術スタック、ネットワーク構造を把握
- マッピング(Mapping): 攻撃対象面(Attack Surface)の特定
- 脆弱性発見(Discovery): 自動化ツールと手動テストの併用
- 脆弱性検証(Exploitation): 発見された脆弱性の実際のリスクを検証
- 報告(Reporting): 技術的な詳細とビジネスへの影響を報告
有用なツール
| ツール | 用途 |
|---|---|
| Burp Suite | Webプロキシ、脆弱性スキャナー |
| Nmap | ネットワークスキャン |
| sqlmap | SQLインジェクション自動化 |
| Nuclei | テンプレートベースの脆弱性スキャン |
| Metasploit | ペネトレーションテストフレームワーク |
バグバウンティプログラム
自社サービスの脆弱性を外部のセキュリティ研究者が発見した場合に報酬を提供するプログラムです。
- HackerOne: 世界最大のバグバウンティプラットフォーム
- Bugcrowd: クラウドソーシングセキュリティテスト
- 自社運営: 明確なスコープと報酬基準の設定が重要です
CTF(Capture The Flag)おすすめ
セキュリティスキルを磨けるCTFプラットフォームです。
- OverTheWire: 基礎から上級まで段階的なウォーゲーム
- Hack The Box: 実践型ペネトレーションテスト環境
- PicoCTF: 初心者に適した教育用CTF
- PortSwigger Web Security Academy: 無料のWebセキュリティ学習プラットフォーム
11. インシデント対応
セキュリティインシデント対応手順(NIST SP 800-61)
フェーズ1: 準備(Preparation)
- インシデント対応チーム(IRT)の編成
- 対応計画の策定と訓練
- 連絡体制とエスカレーション手順の定義
フェーズ2: 検知と分析(Detection and Analysis)
- SIEM(Security Information and Event Management)による異常検知
- ログ分析とIoC(Indicators of Compromise)の特定
- インシデントの範囲と影響度の把握
フェーズ3: 封じ込め、根絶、復旧(Containment, Eradication, Recovery)
# 緊急対応例: 漏洩したAPIキーの無効化
# 1. 影響を受けたキーを直ちに無効化
aws iam delete-access-key --user-name compromised-user --access-key-id AKIA...
# 2. 関連する全セッションの無効化
aws iam put-user-policy --user-name compromised-user \
--policy-name DenyAll --policy-document file://deny-all.json
# 3. 新しい認証情報を発行し、安全に配布
フェーズ4: 事後活動(Post-Incident Activity)
- ポストモーテムレポートの作成
- タイムラインの再構築
- 根本原因分析(Root Cause Analysis)
- 再発防止策の策定と実施
デジタルフォレンジックの基礎
- 証拠保全の原則: 原本を毀損せず、コピーで分析します
- Chain of Custody: 証拠の取り扱い履歴を文書化します
- 収集方法の理解: メモリダンプ、ディスクイメージング、ネットワークトラフィックキャプチャ
- 主要ツール: Volatility(メモリ分析)、Autopsy(ディスク分析)、Wireshark(ネットワーク分析)
セキュリティインシデント報告書の構造
優れたインシデント報告書には以下の項目が含まれます。
- インシデント概要: 発生日時、種類、影響範囲
- タイムライン: 初期侵入から発見までの時系列記録
- 技術分析: 攻撃ベクトル、悪用された脆弱性、攻撃者の行動
- 影響分析: 漏洩データの種類と規模、ビジネスへの影響
- 対応措置: 実施した対応策とその効果
- 再発防止: 短期/長期の改善事項
- 教訓: 対応プロセスでの改善点
まとめ
アプリケーションセキュリティは、単一のツールやプロセスではなく、文化であり旅です。核心原則をまとめます。
- 多層防御(Defense in Depth): 1つのセキュリティ層が失敗しても、他の層が防御を続けます
- 最小権限(Least Privilege): 必要最小限の権限のみを付与します
- フェイルセキュア(Fail Secure): システム障害時にセキュリティが維持される方向で設計します
- ゼロトラスト(Zero Trust): ネットワーク位置に関係なく、すべてのリクエストを検証します
- セキュリティは文化: すべてのチームメンバーがセキュリティ意識を持ち、継続的に学習します
セキュリティ脅威は絶えず進化しています。このガイドを出発点として、継続的な学習と実務適用を並行して進めてください。
クイズ: アプリケーションセキュリティの知識チェック
Q1. OWASP Top 10(2021)で1位にランクされた脆弱性は何ですか?
A: Broken Access Control(アクセス制御の不備)。認可されていないユーザーが他のユーザーのデータにアクセスしたり、管理者機能を実行できる脆弱性です。
Q2. パスワードのハッシュ化にMD5を使ってはいけない理由は?
A: MD5は速度が速すぎるため、ブルートフォース攻撃に脆弱です。bcryptやArgon2のように意図的に遅く設計されたアルゴリズムを使用すべきです。
Q3. JWTでalg: none攻撃を防ぐにはどうすればよいですか?
A: トークン検証時に許可するアルゴリズムを明示的に指定する必要があります。ライブラリのデフォルト設定に依存せず、algorithms=["RS256"]のように具体的に指定します。
Q4. SASTとDASTの違いは何ですか?
A: SAST(静的)はソースコードを実行せずに分析して脆弱性を発見します。DAST(動的)は実行中のアプリケーションに対して外部から攻撃をシミュレーションします。両方を相補的に使用すべきです。
Q5. SSRF攻撃を防御する最も効果的な方法は?
A: 許可されたURLのホワイトリストを適用し、内部ネットワークIP帯(10.x、172.16.x、192.168.x、127.0.0.1)へのリクエストをブロックします。DNS Rebinding攻撃への対策も必要です。