FlawOpen

flawopen.com/Swift の XSS/loadHTMLString

iOS の WKWebView.loadHTMLString は未信頼コンテンツに安全ですか?

リファレンスページ
結論

自動的に安全になるわけではありません。WKWebView は渡された文字列を HTML として解析するため、信頼できる内容であるか、適切な文脈向けに処理されない限り、タグやスクリプトを実行できるマークアップは有効です。通常のテキストとユーザー作成のリッチ HTML には異なる対策が必要です。

安全な使い方

RISKY
let html = "

\(untrustedText)

" webView.loadHTMLString(html, baseURL: nil)
SAFER
func escapeHTMLText(_ value: String) -> String {
    value
        .replacingOccurrences(of: "&", with: "&")
        .replacingOccurrences(of: "<", with: "<")
        .replacingOccurrences(of: ">", with: ">")
        .replacingOccurrences(of: "\"", with: """)
        .replacingOccurrences(of: "'", with: "'")
}

let html = "

\(escapeHTMLText(untrustedText))

" webView.loadHTMLString(html, baseURL: nil)

追加で確認するリスク

ページのワールドに登録したメッセージハンドラーは、ページスクリプトからアプリコードへの経路になります。`WKContentWorld` は JavaScript 環境を分離できますが、ページとアプリのスクリプトは DOM を共有します。未信頼 HTML とブリッジを併用するなら、必要最小限の機能だけを公開し、メッセージと frame を検証して各操作を認可してください。ワールド分離を認可と混同しないでください。

baseURL が制御するもの

Apple は `baseURL` を、渡された HTML 内の相対 URL を解決するための基準として説明しています。マークアップを無害化したり、ページの JavaScript を無効にしたりはしません。`nil` は XSS 対策やサンドボックス設定ではありません。リソースとナビゲーションのポリシーは別に決めてください。

境界ごとに対策を選ぶ

HTML のテキストノードに通常の文字列を入れる場合は、以下のようなその文脈専用のエンコーダーを使い、属性、URL、CSS、JavaScript には流用しないでください。ユーザー入力のリッチ HTML には、要素、属性、URL スキームを明示的に許可する保守されたサニタイザーを使います。アプリ側 JavaScript には `callAsyncJavaScript` の引数で値を渡し、ソース文字列に補間しません。`WKContentWorld` は JavaScript 環境を分離しますが DOM は共有するため、ネイティブ操作の認可にはなりません。ブリッジは最小限にし、各メッセージと操作を検証してください。ページ JavaScript が不要なら `allowsContentJavaScript` で追加防御として無効化できますが、適切な出力処理の代わりにはなりません。

よくある質問

非推奨の UIWebView なら違いますか?

いいえ。同じリスクがあり、追加のサニタイズ機能もありません。WKWebView への移行は技術の近代化であり、それだけで安全になるわけではありません。

`baseURL: nil` で XSS を防げますか?

いいえ。Apple は `baseURL` を相対 URL の解決用として説明しています。HTML サニタイザー、スクリプト切替、サンドボックス保証ではありません。

`WKContentWorld` はページ DOM を分離しますか?

いいえ。JavaScript 環境は分離しますが、DOM は共有されます。DOM のデータやメッセージは信頼せず、各ネイティブ操作を個別に認可してください。

参考資料

関連項目 クロスサイトスクリプティング(XSS、CWE-79)の仕組みと各言語での防ぎ方 — flawopen.com 反射型・格納型・DOM ベース XSS の違いは? Android addJavascriptInterface のセキュリティリスク Angular の XSS 対策:安全な既定動作とバイパス API MIME sniffing XSS:Content-Type と nosniff CSP と出力エスケープ:両方必要ですか? ReactのdangerouslySetInnerHTMLは安全?