[開発者向け]CodeQLでCORSの脆弱性を見つける:フレームワークのモデル化による静的解析の実践

目次

はじめに

 本稿では、Webアプリケーションのセキュリティにおいて重要な役割を担うCORS(Cross-Origin Resource Sharing)の設定不備に起因する脆弱性を、静的解析ツールであるCodeQLを用いてどのように発見できるかを解説します。特に、多くの開発現場で利用されているCORSフレームワークの動作をCodeQLで「モデル化」し、より高度な解析を行う手法に焦点を当てます。

参考記事

要点

  • CORSの不適切な設定は、攻撃者による認証情報の窃取や認証バイパスといった深刻なセキュリティ脆弱性の原因となる。
  • CodeQLは、ソースコードを実行せずにコードの構造や意味(セマンティクス)を理解して解析できる、強力な静的解析エンジンである。
  • CodeQLでCORSの脆弱性を効果的に検出するためには、HTTPヘッダーを手動で設定するコードや、利用しているCORSフレームワークの動作を「モデル化」することが極めて重要である。
  • モデル化とは、特定の関数呼び出しやデータ構造が、セキュリティの文脈においてどのような意味を持つのかをCodeQLに定義する作業のことである。
  • このモデル化に基づいたカスタムクエリを作成することで、単純な設定ミスから、特定のフレームワークの挙動に依存する複雑なロジック上の欠陥まで、網羅的に検出することが可能となる。

詳細解説

そもそもCORSとは?

 CORSの解説に入る前に、Webの基本的なセキュリティモデルである「同一オリジンポリシー(Same-Origin Policy)」について簡単に説明します。これは、あるオリジン(プロトコル、ホスト、ポートの組み合わせ)から読み込まれた文書やスクリプトが、他のオリジンのリソースにアクセスすることを制限する仕組みです。これにより、悪意のあるWebサイトが、ユーザーがログインしている別のサイトの情報を勝手に読み取ったり操作したりすることを防いでいます。

 しかし、現代のWebアプリケーションでは、APIサーバーとフロントエンドでドメインを分けるなど、異なるオリジン間で意図的にリソースを共有したいケースが頻繁にあります。この同一オリジンポリシーの制約を安全に緩和するための仕組みがCORSです。サーバーが特定のHTTPヘッダー(Access-Control-Allow-Originなど)をレスポンスに含めることで、どのオリジンからのアクセスを許可するかをブラウザに伝えます。この設定を誤ると、意図しないWebサイトからのアクセスを許可してしまい、脆弱性につながります。

CodeQLとは? – コードでコードを解析する

 CodeQLは、GitHubによって開発されたセマンティックコード分析エンジンです。ソースコードをデータベースとして扱い、専用のクエリ言語(QL)を使って問い合わせることで、脆弱性やバグ、その他の問題点を発見します。

 grepのようなテキスト検索ツールが特定の文字列を探すだけなのに対し、CodeQLは「この変数はどこで定義されたか」「この関数はどこから呼び出されているか」「ユーザーからの入力が、最終的に危険な関数に渡されているか」といった、コードの構造やデータフローを理解した上での解析が可能です。このような手法を静的解析と呼び、アプリケーションを実行することなく、開発の早い段階でセキュリティリスクを発見できる利点があります。

CodeQLによるCORS脆弱性の検出アプローチ

 CodeQLでCORSの設定ミスを見つけるには、CORSポリシーがどのようにコード上で定義されているかをCodeQLに教える、すなわち「モデル化」する作業が必要になります。主なアプローチは「ヘッダーのモデル化」と「フレームワークのモデル化」の2つです。

1. ヘッダーのモデル化

 最も基本的なCORSの実装は、HTTPレスポンスヘッダーを直接設定する方法です。例えば、Go言語の標準的なHTTPライブラリを使った以下のコードは、あらゆるオリジンからのアクセスを許可してしまいます。

func saveHandler(w http.ResponseWriter, r *http.Request) { 
    w.Header().Set("Access-Control-Allow-Origin", "*") 
}

 このコード自体は、認証を必要としない公開APIなどでは問題ありません。しかし、認証が必要な内部向けツールなどにこの設定が使われていると、悪意のあるサイトからリクエストを送信され、意図しない操作をされる可能性があります。

 CodeQLでは、このようなヘッダー書き込み操作をモデル化するための仕組みが用意されています。HTTP.qllというライブラリ内のHeaderWriteクラスなどを拡張することで、「w.Header().Set(…)というコードは、HTTPヘッダーを書き込む操作である」と定義できます。

 さらに危険なのは、リクエスト元のOriginヘッダーの値をそのままAccess-Control-Allow-Originに設定(反射)し、かつ認証情報(Cookieなど)の送信を許可するAccess-Control-Allow-Credentialsをtrueにするパターンです。

func saveHandler(w http.ResponseWriter, r *http.Request) { 
    // リクエストのOriginヘッダーをそのまま許可する
    w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))

    // 資格情報の送信を許可する
    w.Header().Set("Access-Control-Allow-Credentials", "true") 

}

 この設定では、攻撃者のウェブサイトが、ユーザーのブラウザを使って正規のサイトに認証情報付きのリクエストを送信し、その結果を盗み見ることが可能になってしまい、非常に危険です。CodeQLでは、このような危険な組み合わせを検出するクエリを作成します。

2. フレームワークのモデル化

 実際には、ヘッダーを毎回手動で設定するのではなく、専用のライブラリやフレームワークのミドルウェアを使ってCORSを管理するのが一般的です。参考記事では、Go言語で人気のWebフレームワークであるGinと、そのCORSミドルウェアを例に解説しています。

// GinフレームワークでCORSミドルウェアを使用する例
func main() {
  router := gin.Default()
  router.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"https://foo.com"},
    AllowMethods:     []string{"PUT", "PATCH"},
    AllowHeaders:     []string{"Origin"},
    ExposeHeaders:    []string{"Content-Length"},
    AllowCredentials: true, // 資格情報を許可
    AllowOriginFunc: func(origin string) bool {
       // 特定のオリジンのみを許可するカスタム関数
       return origin == "https://github.com" 
    },
  }))
  router.Run()
}

 このようなフレームワークの利用を解析するには、cors.Configという構造体や、cors.New、router.Useといった関数がCORSポリシーの設定において重要な役割を果たすことをCodeQLに教える必要があります。

 参考記事では、cors.Config型の変数を追跡し、その中のAllowOriginsやAllowCredentialsといったフィールドにどのような値が設定されているかを特定するモデルを作成しています。例えば、AllowOriginsWriteというクラスを定義し、「cors.Config構造体のAllowOriginsフィールドへの書き込み」を表現します。

 このようにフレームワーク固有のAPIをモデル化することで、「AllowCredentialsがtrueに設定されているcors.Configが、脆弱なAllowOriginsの設定(例えば、任意のオリジンを許可するようなカスタム関数)と同時に使われている箇所」といった、より複雑で現実に即した脆弱性パターンを検出するクエリが書けるようになります。

脆弱性検出クエリの作成

 モデル化が完了したら、それらを組み合わせて脆弱性を検出するクエリを作成します。Go言語用のCORSクエリのロジックは、おおよそ以下のようになっています。

  1. 資格情報(Credentials)が許可されているか?
    • Access-Control-Allow-Credentialsヘッダーがtrueに設定されているか?
    • または、フレームワークのモデル(UniversalAllowCredentialsWriteなど)で、資格情報が許可されているか?
  2. 許可するオリジン(Origin)の指定が脆弱か?
    • 許可するオリジンがnullにハードコードされているか?
    • または、外部からの信頼できない入力(リクエストヘッダーなど)が、適切な検証なしに許可オリジンとして使われていないか?
  3. 上記1と2の両方を満たすか?

 このクエリにより、前述した「Originの反射」のような危険な設定をコードベースから探し出すことができます。また、フレームワークごとに異なる挙動(例えば、AllowOriginFuncがAllowOriginsの設定を上書きするなど)を考慮してモデルやクエリを調整することで、解析の精度をさらに高めることができます。

AIシステム特有のCORS脆弱性リスク

1. マルチサービス・アーキテクチャの複雑性

AIシステムは通常、以下のような複数のサービスで構成されます:

  • モデルサービング API(推論エンドポイント)
  • データ前処理サービス
  • モデル管理ダッシュボード(Web UI)
  • 実験追跡システム(MLflow、Weights & Biases等)
  • リアルタイム監視システム

これらが異なるドメイン・ポートで動作することが多く、各サービス間でのCORS設定が複雑になります。

# FastAPIでの機械学習モデルサービング例
@app.post("/predict")
async def predict(request: PredictionRequest):
    # 危険な例:すべてのオリジンを許可
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Credentials"] = "true"
    result = ml_model.predict(request.features)
    return {"prediction": result}

2. 機密データの露出リスク

AIシステムでは特に機密性の高いデータを扱うため、CORS設定不備による影響が深刻になります:

  • 学習データの流出:訓練に使用した個人情報や企業機密
  • モデル出力の盗用:推論結果から逆算される商業機密
  • モデル自体の窃取:APIレスポンスからのモデル構造推測

3. 実験環境と本番環境の設定差異

AI開発では実験的なプロトタイプを頻繁に作成するため、開発時の緩い設定が本番に流用されるリスクがあります。

# 開発時によくある危険なパターン
if os.getenv("ENVIRONMENT") == "development":

    # 開発時は全許可(危険!)
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

まとめ

 本稿では、GitHubブログの記事を参考に、CodeQLを用いてCORSの設定不備に起因する脆弱性を発見する手法について解説しました。

 重要なのは、CodeQLのような静的解析ツールを最大限に活用するためには、単にツールを実行するだけでなく、対象となるコードベースで使われているライブラリやフレームワークの動作を「モデル化」し、ツールに学習させることが不可欠であるという点です。このモデル化というアプローチは、CORSに限らず、SQLインジェクションやXSS(クロスサイトスクリプティング)など、他の様々な脆弱性を発見する上でも非常に有効な手法です。

  AIシステム開発では、従来のWebアプリケーション以上にCORSセキュリティが重要になります。CodeQLを活用して、AI/MLフレームワーク特有のパターンをモデル化し、開発チーム全体でセキュリティ意識を共有することが、安全なAIシステム構築の鍵となります。特に、実験的な開発が多いAI分野では、セキュリティ設定が後回しになりがちですが、早期からCodeQLのような静的解析ツールを導入することで、セキュリティバイデザインを実現できます。

 CodeQLを使いこなすことで、開発者はセキュリティ専門家だけに頼るのではなく、自らの手でコードの品質と安全性を向上させることができます。

この記事が気に入ったら
フォローしてね!

  • URLをコピーしました!
  • URLをコピーしました!
目次