Skip to main content

サービス拒否を引き起こす正規表現がFastAPIのセキュリティを脅かす

著者
feature python linting

2024年7月31日

0 分で読めます

開発者の皆さん、こんにちは!この記事では、アプリケーションセキュリティの世界を掘り下げ、FastAPIのセキュリティを損なう可能性のある脆弱性、つまり安全でない正規表現(regex)によるサービス拒否(DoS)に焦点を当てます。適切に構築されていない正規表現が、DoS攻撃の一種である正規表現サービス拒否(ReDoS)につながる仕組みと、強力な開発者向けセキュリティツールであるSnykを使って、こうした脆弱性を検出し、緩和する方法を解説します。

ReDoSとは何ですか?

ReDoSは、評価に非常に長い時間がかかる正規表現を利用してサービス拒否を引き起こす、アルゴリズム計算量攻撃です。攻撃者は、脆弱な正規表現で処理されるWebフォームの入力欄やURLのクエリパラメーターに、悪意のある文字列を送信します。正規表現が文字列の処理に要する時間は多項式時間を超え、多くの場合、入力サイズに対してほぼ指数関数的に増加します。そのため処理に非常に長い時間がかかり、サービス拒否が発生します。

PythonにおけるReDoSがFastAPIのセキュリティに与える影響

人気の高いプログラミング言語の一つであるPythonには、膨大なパッケージやライブラリのエコシステムがあります。これらのパッケージは開発者の作業を楽にしてくれますが、適切に保護されていない場合は潜在的なリスクにもなります。ソフトウェア開発が急速に進むなか、パッケージは頻繁に更新され、新しいバージョンがリリースされます。その際、気づかないうちにセキュリティリスクが持ち込まれることもあります。

そうしたリスクの一つがReDoS攻撃です。これは、攻撃者が正規表現に悪意のある入力を渡し、その評価に非常に長い時間がかかるようにするDoS攻撃の一種です。その結果、アプリケーションが応答しなくなったり、大幅に遅くなったりして、ユーザー体験の低下からアプリケーションの完全な停止に至るまで、深刻な影響が生じる可能性があります。

import re
pattern = re.compile("^(a+)+$")
def check(input):
    return bool(pattern.match(input))
check("a" * 3000 + "!")

上記のコードでは、正規表現^(a+)+$がReDoS攻撃に対して脆弱です。攻撃者が「a」が連続する文字列の後に「a」以外の文字を付けて入力すると、正規表現の評価に非常に長い時間がかかり、実質的にDoSを引き起こします。

SnykでFastAPIのPythonアプリケーションを保護する方法

Snykは開発者を第一に考えたセキュリティツールで、PythonコードをスキャンしてReDoSの潜在的な脆弱性を検出できます。検出された脆弱性について詳細なレポートを提供し、最適な修正方法を提案します。

# After installing Snyk and setting up the Snyk CLI
# you can scan your project:
$ snyk test 

このコマンドは、通常requirements.txtファイルに記載されているサードパーティ依存関係のマニフェストをスキャンし、ReDoSの潜在的な脆弱性を含む、検出されたすべての脆弱性のレポートを出力します。Snykの無料アカウントに登録して、今すぐPythonプロジェクトのReDoSなどの脆弱性をスキャンしましょう。

こうした脆弱性の影響と緩和方法を理解することは、安全なPythonアプリケーションを維持するうえで欠かせません。そこで役立つのがSnykのようなツールです。Snyk Open Sourceは、ReDoS攻撃につながる可能性のある安全でない正規表現を含め、Pythonパッケージのセキュリティ脆弱性の検出と修正を支援します。

Snykを使って、FastAPIのPythonウェブアプリケーションでこうした脆弱性を特定し、緩和する方法を詳しく見ていきましょう。

CVE-2024-24762に関連するFastAPIのセキュリティ脆弱性

FastAPIは、標準的なPython型ヒントに基づいてPythonでAPIを構築するための、最新の高性能ウェブフレームワークです。高速で、堅牢なAPIをすばやく簡単に構築できることが主な特長であり、高性能なRESTful APIを構築する必要があるPython開発者に人気です。

FastAPIは、ルーティング、シリアライズ/デシリアライズ、バリデーションの機能を標準で備え、API構築を簡素化します。ウェブ機能にはPythonプロジェクトのStarlette、データ機能にはPydanticを基盤としており、Python 3.6以降で利用できる非同期機能を活用できます。

たとえば、FastAPIを使ったPythonウェブアプリケーションでシンプルなAPIを作成するには、次のコードを使用します。

from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
    return {"Hello": "World"}

FastAPIはAPI開発に適した堅牢で柔軟なツールですが、脆弱性がないわけではありません。その一つがCVE-2024-24762への脆弱性です。これは、Pythonパッケージpython-multipartで使用される正規表現に起因するサービス拒否の脆弱性です。

依存関係のpython-multipartは、multipart/form-dataを解析するPythonライブラリです。FastAPIでは、フォームデータを処理するための依存関係として一般的に使用されています。

攻撃者が悪意のある文字列を送信すると、python-multipartの正規表現が大量のCPUリソースを消費し、サービス拒否(DoS)を引き起こす可能性があります。これは正規表現サービス拒否(ReDoS)とも呼ばれます。

Python開発者は、この脆弱性をどのように緩和できるでしょうか。最初のステップは、プロジェクト内の脆弱性を特定することです。Snyk CLIツールを使って特定できます。

$ snyk test

このような脆弱性を検出するには、プロジェクトの依存関係をスキャンする必要があります。スキャンにより、プロジェクトの依存関係に含まれるすべての脆弱性のレポートが生成されます。

snyk testコマンドを実行すると、次のように脆弱性が検出されます。

snyk test

Testing /Users/lirantal/projects/repos/fastapi-vulnerable-redos-app...

Tested 13 dependencies for known issues, found 1 issue, 1 vulnerable path.

Issues to fix by upgrading dependencies:

  Upgrade fastapi@0.109.0 to fastapi@0.109.1 to fix
  ✗ Regular Expression Denial of Service (ReDoS) (new) [High Severity][https://security.snyk.io/vuln/SNYK-PYTHON-FASTAPI-6228055] in fastapi@0.109.0
    introduced by fastapi@0.109.0

Organization:      liran.tal
Package manager:   pip
Target file:       requirements.txt
Project name:      fastapi-vulnerable-redos-app

脆弱性を修正するには、脆弱性が修正された新しいバージョンのpython-multipartとfastapiにアップグレードします。Snykは、アップグレード先のバージョンを提案します。

CVE-2024-24762の脆弱性はFastAPIアプリケーションにどのような影響を与えますか?

CVE-2024-24762の脆弱性は、FastAPIフレームワークにおけるReDOS脆弱性を示す仮想的な例です。脆弱な正規表現を使用するエンドポイントに攻撃者が悪意のある入力を送ると、FastAPIアプリケーションが過剰なリソースを消費して応答しなくなり、実質的に停止に追い込まれる可能性があります。

FastAPIのセキュリティを構築し、検証する:ステップごとのガイド

まず、新しいPythonプロジェクトをセットアップします。FastAPIと、アプリケーションをホストするサーバーをインストールする必要があります。Uvicornは軽量でFastAPIとの相性も良いため、サーバーとして適しています。

まず、pipでFastAPI、python-multipart、Uvicornをインストールします。

pip install fastapi==0.109.0 uvicorn python-multipart==0.0.6

次に、プロジェクト用の新しいディレクトリを作成し、その中にFastAPIアプリケーション用のファイルを作成します。ファイル名はmain.pyにします。

FastAPIのPythonコードを作成する

これでFastAPIアプリケーションのコードを作成できます。main.pyを開き、次のPythonコードを追加します。

from typing import Annotated
from fastapi.responses import HTMLResponse
from fastapi import FastAPI,Form
from pydantic import BaseModel

class Item(BaseModel):
    username: str

app = FastAPI()

@app.get("/", response_class=HTMLResponse)
async def index():
    return HTMLResponse("Test", status_code=200)

@app.post("/submit/")
async def submit(username: Annotated[str, Form()]):
    return {"username": username}

@app.post("/submit_json/")
async def submit_json(item: Item):
    return {"username": item.username}

このシンプルなFastAPIアプリケーションには、/submitなど複数のルート(/)があります。このルートではmultipartフォームを使用します。POSTリクエストを受信すると、submitルートは送信されたユーザー名を返します。

サーバーを起動してアプリケーションを実行する

FastAPIアプリケーションのコードを作成したので、Uvicornサーバーを起動してアプリケーションを実行できます。

次のコマンドでサーバーを起動します。

uvicorn main:app --reload

サーバーが実行中であることを示す出力が表示されます。ウェブブラウザーでhttp://localhost:8000にアクセスして、アプリケーションをテストできます。ページに「Test」と表示されます。

ReDoS攻撃でFastAPIのセキュリティを破る

FastAPIアプリケーションが起動したら、脆弱性をテストできます。HTTPリクエストにReDoS攻撃のペイロードを使い、content-typeヘッダー値を解析するpython-multipartパッケージの脆弱性を悪用します。

curlプログラムがインストールされている場合は、ターミナルで次のコマンドを実行します。

curl -v -X 'POST' -H $'Content-Type: application/x-www-form-urlencoded; !=\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' --data-binary 'input=1' 'http://localhost:8000/submit/'

SnykでFastAPIアプリケーションを保護する

ここまで見てきたように、オープンソースの依存関係はPythonアプリケーションの構築において重要な役割を果たします。しかし、こうしたサードパーティの依存関係が脆弱性の温床となり、重大なセキュリティ脅威をもたらすことがあります。Snyk Open Sourceは、開発者がセキュリティ問題を効果的に特定し、修正するための堅牢なツールです。

セキュリティスキャナーが後の段階で検出するのを待つのではなく、Pythonコードを書いているときにIDEのパネルでFastAPIのセキュリティ脆弱性をすばやく見つけられるとしたらどうでしょう。

Snyk IDE拡張機能は無料です。PyCharmをお使いの場合は、PluginsビューでSnykを検索して直接ダウンロードできます。VS Codeをお使いの場合も、IDEからExtensionsマーケットプレイスで見つけられます。

IDEでFastAPIのセキュリティ脆弱性を検出。

Snyk Open Sourceとその機能の紹介

Snyk Open Sourceは、オープンソースの依存関係やコンテナイメージの脆弱性を見つけて対処するための強力なツールです。既存のコードベースやCI/CDシステムに簡単に統合できるよう設計されており、開発者にとって便利なツールです。既知の脆弱性を網羅したデータベースを提供し、開発者がセキュリティ侵害の可能性に先回りして対処できるよう支援します。

SnykでPythonの依存関係をスキャンして脆弱性を検出するステップごとのガイド

SnykでPythonの依存関係の脆弱性をスキャンするには、まずSnyk CLIをインストールします。ガイドに記載されているいずれかの方法でインストールできます。Node.js環境がある場合は、npm install -g snykでSnykをすばやくインストールし、続けてrun snyk authを実行して認証できます。

インストール後、snyk testコマンドを実行して、Pythonプロジェクトの脆弱性を確認できます。

snyk test --all-projects

Snykはすべての依存関係をスキャンし、脆弱性データベースと照合します。問題が見つかった場合は、脆弱性の詳細、深刻度、修正方法を含むレポートを提供します。

アプリケーションのセキュリティを維持するには、Snykでプロジェクトを監視することが重要です。Snykを使えば、脆弱性を検出できるだけでなく、自動修正も適用できるため、時間とリソースを節約できます。

さらに、Snykは新たに発見された脆弱性がプロジェクトに影響する可能性がある場合に通知します。これにより、脆弱性が悪用される前にセキュリティ問題を修正し、先手を打つことができます。

snyk monitorコマンドを使うと、現在のプロジェクトの依存関係のスナップショットを作成し、脆弱性を監視できます。

snyk monitor

SnykをGitリポジトリと連携する方法

SnykをGitリポジトリと連携すると、コミットごとに脆弱性を自動スキャンできます。リポジトリの設定でSnykをWebhookとして追加することで実現できます。

SnykはGitHubやGitリポジトリと連携し、プルリクエストをチェックしてFastAPIのセキュリティ脆弱性を防ぎます。

設定が完了すると、リポジトリへのプッシュのたびにSnykのスキャンが実行され、脆弱性をできるだけ早く検出して修正できます。

まとめると、Snyk Open SourceはPythonプロジェクトのセキュリティ維持に役立つツールです。脆弱性のスキャン、プロジェクトの監視、Gitリポジトリとの連携を通じて、Snykは堅牢で安全なコードベースの維持を支援します。まだ登録していない方は、Snykの無料アカウントに登録して、今すぐアプリケーションの保護を始めましょう。

CTFを始めよう

オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。