【2026年版】Webセキュリティ完全ガイド|OWASP Top 10・XSS・SQLインジェクション・CSRFの対策コード付き解説

Webセキュリティは現代のエンジニアに必須のスキルです。2026年現在、サイバー攻撃の被害額は世界で年間10兆ドル以上に達し、中小企業を含むあらゆる組織が標的になっています。本記事では、最も重要なWebセキュリティの脅威と対策を、実際のコード例とともに徹底解説します。

OWASP Top 10(2026年版)

  1. A01: アクセス制御の不備(最多発生)
  2. A02: 暗号化の失敗(機密データの平文送受信など)
  3. A03: インジェクション(SQLi、XSS、コマンドインジェクション)
  4. A04: 安全でない設計(脅威モデリングの不備)
  5. A05: セキュリティ設定のミス(デフォルト設定使用など)
  6. A06: 脆弱なコンポーネント(既知の脆弱性を持つライブラリ使用)
  7. A07: 認証・セッション管理の不備
  8. A08: ソフトウェア・データの整合性の失敗
  9. A09: セキュリティログ・監視の失敗
  10. A10: サーバーサイドリクエストフォージェリ(SSRF)

SQLインジェクション対策

脆弱なコード(絶対NG)

# 危険:文字列連結でSQLを構築
def get_user_vulnerable(username: str):
    query = f"SELECT * FROM users WHERE username = '{username}'"
    # username = "' OR '1'='1" のような攻撃が成立してしまう!
    return db.execute(query)

安全なコード(パラメータ化クエリ)

# 正しい:パラメータ化クエリを使用
def get_user_safe(username: str):
    query = "SELECT * FROM users WHERE username = %s"
    return db.execute(query, (username,))  # プレースホルダーを使用

# SQLAlchemyでの例(ORM)
from sqlalchemy.orm import Session

def get_user_with_sqlalchemy(db: Session, username: str):
    return db.query(User).filter(User.username == username).first()

# 入力値バリデーション
import re
from pydantic import BaseModel, validator

class LoginRequest(BaseModel):
    username: str
    password: str

    @validator('username')
    def validate_username(cls, v):
        if not re.match(r'^[a-zA-Z0-9_-]{3,20}$', v):
            raise ValueError('ユーザー名は英数字・アンダースコア・ハイフンのみ(3〜20文字)')
        return v

XSS(クロスサイトスクリプティング)対策

// React(JSX)は自動エスケープなので基本安全
// ただしdangerouslySetInnerHTMLは危険
const SafeComponent = ({ userInput }) => (
  // NG: <div dangerouslySetInnerHTML={{ __html: userInput }} />
  <div>{userInput}</div>  // OK: 自動エスケープされる
);

// HTMLを動的に生成する場合はDOMPurifyを使用
import DOMPurify from 'dompurify';

const SafeHTML = ({ htmlContent }) => {
  const sanitized = DOMPurify.sanitize(htmlContent, {
    ALLOWED_TAGS: ['p', 'br', 'b', 'i', 'a'],
    ALLOWED_ATTR: ['href', 'target'],
  });
  return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
};

// Content Security Policy(CSP)ヘッダー設定(Next.js例)
// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: [
      "default-src 'self'",
      "script-src 'self' 'unsafe-inline' https://www.googletagmanager.com",
      "style-src 'self' 'unsafe-inline'",
      "img-src 'self' data: https:",
      "font-src 'self'",
      "connect-src 'self' https://api.example.com",
    ].join('; ')
  },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
];

認証・セッション管理のベストプラクティス

import jwt
import bcrypt
from datetime import datetime, timedelta
from fastapi import HTTPException, Depends
from fastapi.security import HTTPBearer

SECRET_KEY = "your-super-secret-key-change-this!"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# パスワードハッシュ化(bcrypt)
def hash_password(password: str) -> str:
    salt = bcrypt.gensalt(rounds=12)  # コスト係数12
    return bcrypt.hashpw(password.encode(), salt).decode()

def verify_password(plain_password: str, hashed: str) -> bool:
    return bcrypt.checkpw(plain_password.encode(), hashed.encode())

# JWTトークン生成
def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
    to_encode.update({"exp": expire, "iat": datetime.utcnow()})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

# レート制限(ブルートフォース対策)
from functools import wraps
import time
from collections import defaultdict

login_attempts = defaultdict(list)

def rate_limit(max_attempts: int = 5, window: int = 300):
    def decorator(func):
        @wraps(func)
        async def wrapper(request, *args, **kwargs):
            ip = request.client.host
            now = time.time()
            attempts = [t for t in login_attempts[ip] if now - t < window]
            if len(attempts) >= max_attempts:
                raise HTTPException(
                    status_code=429,
                    detail=f"{window//60}分後に再試行してください"
                )
            login_attempts[ip].append(now)
            return await func(request, *args, **kwargs)
        return wrapper
    return decorator

セキュリティ診断ツール

ツール用途価格
OWASP ZAPWebアプリの脆弱性スキャン無料
Burp Suite Communityプロキシ・脆弱性テスト無料/有料
Nmapポートスキャン・ネットワーク調査無料
Trivyコンテナ・IaCの脆弱性スキャン無料
Snyk依存関係の脆弱性チェック無料/有料

まとめ

Webセキュリティは後付けでは対処が難しく、設計段階から組み込む「Security by Design」が重要です。OWASPのガイドラインを参考に、パラメータ化クエリの使用、XSS対策、適切な認証・セッション管理を実装し、定期的なセキュリティ診断を行いましょう。セキュリティスキルを持つエンジニアは市場価値が高く、年収1,000万円以上の求人も多数あります。

投稿者 kasata

IT企業でエンジニアとして勤務後、テクノロジー情報メディア「Tech Athletes(テック・アスリート)」を運営。プログラミング、クラウドインフラ(AWS/GCP/Azure)、AI活用、Webサービス開発を専門とする。エンジニア・ビジネスパーソン向けに、実際に使ってみた経験をもとに信頼できる技術情報を発信中。資格:AWS認定ソリューションアーキテクト、Python 3 エンジニア認定試験合格。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です