Pythonのstr.lower()がセキュリティ脆弱性になる理由

When str.lower() is a security vulnerability in Python – Seth Larson

Pythonのstr.lower()がセキュリティ脆弱性になる理由

Pythonの標準ライブラリに含まれるIDNA 2003エンコーディング(`.encode('idna')`)には、Unicodeのバージョン差異によって仕様と実装が乖離する脆弱性が存在しました。StringPrepのケースフォールディングはUnicode 3.2.0に基づくべきですが、`str.lower()`は実行環境のUnicodeバージョン(例: 17.0.0)を使用するため、特定の文字で異なる結果を生じます。この問題はCVE-2026-17084として報告され、Pythonの`stringprep`モジュールに例外テーブルを追加することで修正されました。

この関数内の`str.lower()`呼び出しは脆弱性です!なぜなら、`str`はPythonインタープリタが搭載するUnicodeデータを使用するからです。
  1. echoangle

    > これが、str.lower() を呼び出すことが実装と仕様の違いを表しており、したがって脆弱性である理由です:

    これがどのように脆弱性なのか、単に誤ったデータを生成するバグではないのか、何らかの説明があればいいのにと思います。

    脆弱性というと、バグからエクスプロイトを作成する合理的な方法があるように聞こえますが、このトピックにあまり詳しくない者としては、ここにそのような方法は見当たりません。

  2. tialaramex

    この愚行は、Python 関係者に TLS 実装で働く人々が、SAN の定義されたメカニズム(Subject Alternative Name の「代替」は複数という意味ではない。X.509 は元々 X.500 システム用であり、インターネットが X.509 を転用したため、これらはインターネットからの代替名である)が DNS 名であることを理解させることが非常に重要だった理由の大きな部分を占めています。つまり、それらは人間が読めるテキストの一種として解釈されるべきではなく、したがって Unicode に「デコード」することは明らかにナンセンスです。Python はそれを強く望んでいたし、実際にやっていたか、少なくとも提案していたと思いますが。

    SAN DnsNames が DNS からの類似名とどのように一致するかのルールは、非常に単純で、間違えないようになっています。単一のワイルドカード(ASCII コード 42 の * は任意の単一の DNS ラベルに一致)を処理し、それ以外は文字通りのバイト比較です。これらのバイトが何を意味するかは気にしません。バイトがすべて同一であるか、一致しないかのどちらかで、それで終わりです。

  3. ummonk

    > 修正は、str.lower() が特定の関数に対してのみ Unicode 3.2.0 を使用しているかのように動作するように、新しい例外を作成することでした。そこで、各 Unicode コードポイントを調べ、Python に同梱されている Unicode バージョンと Unicode 3.2.0 を比較したときに str.lower() の動作が異なる場合を記録します。

    これは、別の固定された Unicode 3.2.0 の lower を実装するのに比べて、本当にハッキーな解決策に聞こえます。

  4. jooon

    Spotify での古いセキュリティインシデントを思い出します。https://engineering.atspotify.com/2013/06/creative-usernames

  5. ike_sh

    ケルビン記号でこれに遭遇しました。特定するのに恥ずかしいほど時間がかかりました。

この日のほかの記事

2026-08-25