flawopen.com/Ruby YAML/Ruby YAML
信頼できない入力に YAML.load を使っても安全ですか?
アプリケーションが実際に読み込む Psych のバージョンを確認してください。Ruby 3.1 に同梱された Psych 4 は、YAML.load を既定で安全なデシリアライズに変更しました。それ以前の Psych は任意のオブジェクトを構築していました。Psych は Ruby とは別に更新することもできます。YAML.unsafe_load と Marshal.load は Ruby オブジェクトをデシリアライズするため、信頼できない入力に使ってはいけません。
# Psych < 4: YAML.load used unsafe # object construction by default. YAML.load(params[:config]) # Every Psych version: explicitly unsafe. YAML.unsafe_load(user_input) Psych.unsafe_load(user_input) # Marshal has no restricted safe-load API. Marshal.load(cookie_value)
# Explicit restricted types; keep this list minimal. require "yaml" require "date" data = YAML.safe_load( input, permitted_classes: [Date], permitted_symbols: [], aliases: false ) # For ordinary external data, prefer JSON and # validate its shape, values, and input size. data = JSON.parse(input)
YAML が危険になり得る理由
YAML のタグは Psych によって Ruby オブジェクトへ変換されます。安全でない読み込みでは、タグ付き文書がクラスの構築を要求し、シリアライズされた状態の値を指定できます。影響は利用可能なクラスとその動作によって異なり、これがデシリアライズ gadget chain の基礎です。信頼できない YAML には安全な読み込みを使い、返されたデータも別途検証してください。同種のリスクは Python pickle、PHP unserialize、Ruby の Marshal.load にもあります。
Rails などのアプリケーションが多数の依存関係を読み込むと、安全でないデシリアライズチェーンで利用できるクラスや動作が増える場合があります。これはデプロイ環境に左右され、すべての Rails アプリや YAML 文書に当てはまるわけではありません。
バージョン変更が混乱を招いた理由
Psych 4 は YAML.load を既定で安全な読み込みに変更し、従来のオブジェクト構築動作のために unsafe_load を導入しました。Ruby 3.1 には Psych 4 が同梱されましたが、アプリケーションは別の Psych gem を選択できます。Ruby のバージョンだけでなく、解決された依存関係とランタイムを監査してください。安全な読み込みはアプリ固有のクラスや alias を拒否する場合がありますが、unsafe_load に切り替えず、必要最小限の明示的な許可リストで移行します。
アップグレードで unsafe_load が導入された場合、信頼できるデプロイ境界の外から入力を制御できるならセキュリティ上の問題として扱ってください。必要最小限の permitted_classes を指定した safe_load を優先し、互換性エラーを消すためだけに許可範囲を広げないでください。
FAQ
YAML.safe_load は完全に安全ですか?
自分で管理する設定ファイルを読み込む場合は?
Marshal を使ってもよい場合はありますか?
Ruby にある別のリスク:Marshal.load
YAML とは別に、Ruby のドキュメントは Marshal.load がプロセス内のほぼすべての読み込み済みクラスを再構築でき、信頼できないデータではリモートコード実行につながる可能性があると警告しています。Marshal データは信頼境界内にとどめ、ユーザー提供または攻撃者が影響できるバイト列をデシリアライズしないでください。
参考資料
- Ruby documentation — Psych (YAML)
- Psych 4.0 — Ruby 3.1 API documentation
- Ruby documentation — Marshal security considerations
- CVE-2024-35221 — YAML alias denial of service in RubyGems metadata
- CWE-502 — Deserialization of Untrusted Data
- Is Python's pickle safe for untrusted data?
- Is PHP's unserialize() safe on user input?
- Ruby ドキュメント — Marshal.load のセキュリティ警告