SVGヤバイ 2013冬

Chrome 31がStableになって久しい。何が変わったのか思い出せないんだけど、ひとつだけ覚えてるのがこちら。

WebKitのパッチをマージしたものらしい。ちょっとずつ離れているらしいけど、まだお互い共有できるパッチもあるんだね。

さて、このパッチによって、CanvasSVG画像をdrawImage()などで描画したとき、条件によってはそのCanvasがtaintされなくなった。

Tainted Canvasとは

CanvasにはdrawImage()など、画像をCanvasに描画するメソッドがある。ここで、スクリプトとsame-originではないとこにある画像を描画してしまうと、セキュリティ上の都合からCanvasが“tainted”(「汚染」)という扱いになり、getImageData(), toDataURL(), toBlob()などができない。

ハックではない正攻法な対策としては、画像の配置場所をスクリプトとsame-originなところにするのが楽か。もしくはCORSのヘッダを設定してその許可したorigin以下に画像を配置し、それから画像にcrossorigin属性(DOMの場合はcrossOrigin)を指定するなんてやり方もある。詳しくはMDNのドキュメント参照のこと。日本語訳がある。

こんなニッチなの誰が訳したんだと思ったら自分だった…記憶がまったくない。

きたないSVG

さて、originまわりが良くなってもtainted扱いになるなんて場合がある。SVG画像だ。SVGは中にスクリプトや画像を書けちゃうので、危ないと判断されてWebKit/Blinkではこれまでどうあがいてもtainted扱いとなっていた。

あー説明めんどくさい…と思ってたらgyuqueさんが2年半前に同じことを書かれていた。しかもデモつき。なんと。

今回のパッチで、SVG画像が内部で画像を呼んでない場合、そのSVG画像をdrawImage()で読み込んでもtainted扱いにならなくなった。Chrome 31で見てみたところ、一番右の列がすべて「OK」となったのを確認。

図:単純なSVG画像をdrawImage()してもtainted扱いにならなくなった例

マミさんは死んだ。

例で使われている画像的には良い気がしないけど、Webプラットフォーム的には良い変更だ。

試してないけど、SVG画像の中に<svg:image>があるとアウトになるんだろう。

Geckoではだいぶ前からOKだったらしい

Firefoxで見たところこちらもOK(マミさんは死ぬけど)。2011年5月時点ではGeckoでもダメだったようだけど、Geckoでは2011年末に修正され、Firefox 11から使えていたらしい。今回Blinkもサポートされるのでカバー範囲が広がったけど、SafariSafari 8になるだろう。来年かー