Flask のセキュリティヘッダー設定

Web アプリケーションのセキュリティを高めるには、HTTP レスポンスヘッダーを適切に設定することが重要である。Flask でセキュリティヘッダーを設定する方法を解説する。

after_request で設定

@app.after_request
def add_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    return response

主要なセキュリティヘッダー

X-Content-Type-OptionsMIME タイプのスニッフィングを防止
X-Frame-Optionsクリックジャッキング対策
X-XSS-Protectionブラウザの XSS フィルタを有効化
Strict-Transport-SecurityHTTPS を強制
Content-Security-Policy読み込めるリソースを制限

Content-Security-Policy (CSP)

CSP は XSS 攻撃を防ぐ強力な仕組みである。

@app.after_request
def add_csp_header(response):
    csp = (
        "default-src 'self'; "
        "script-src 'self' https://cdn.example.com; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data: https:; "
        "font-src 'self' https://fonts.gstatic.com; "
        "connect-src 'self' https://api.example.com; "
        "frame-ancestors 'none';"
    )
    response.headers['Content-Security-Policy'] = csp
    return response

Flask-Talisman の利用

Flask-Talisman を使えば、セキュリティヘッダーを簡単に設定できる。

pip install flask-talisman
from flask_talisman import Talisman

talisman = Talisman(
    app,
    force_https=True,
    strict_transport_security=True,
    session_cookie_secure=True,
    content_security_policy={
        'default-src': "'self'",
        'script-src': ["'self'", 'cdn.example.com'],
        'style-src': ["'self'", "'unsafe-inline'"],
    }
)

開発環境での注意

HTTPS 強制は開発環境では問題になる。

if app.config['ENV'] == 'production':
    Talisman(app, force_https=True)
else:
    Talisman(app, force_https=False)

Cookie のセキュリティ設定

app.config['SESSION_COOKIE_SECURE'] = True      # HTTPS でのみ送信
app.config['SESSION_COOKIE_HTTPONLY'] = True    # JavaScript からアクセス不可
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'   # クロスサイトリクエストで送信しない

Referrer-Policy

response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'

同一オリジンでは完全な URL を、クロスオリジンではオリジンのみを送信する。

Permissions-Policy

ブラウザの機能(カメラ、マイク、位置情報など)へのアクセスを制限する。

response.headers['Permissions-Policy'] = (
    'geolocation=(), '
    'microphone=(), '
    'camera=()'
)

セキュリティヘッダーを適切に設定することで、多くの攻撃ベクトルを事前に防ぐことができる。