JavaScriptをPNGに圧縮するテクニック 33
ストーリー by hylom
素人にはおすすめしない 部門より
素人にはおすすめしない 部門より
JavaScriptをPNG画像に変換することで圧縮するテクニックとそのためのツール「JS Packer」が公開されている(JavaScript を PNG に圧縮する)。
デモシーンと呼ばれる、プログラム技術とグラフィックや音楽製作技術を組み合わせてデモを作成する分野での利用を想定しているようだ。JavaScriptコード中の文字を色に置き換えた画像を8ビットPNG形式で圧縮する、というもので、オリジナルのJavaScriptファイルよりもサイズを小さくでき、簡単にエンコード/デコードできるというのが特徴。ただし多くの場合GZIPのほうが圧縮率が高くなるとのことで、一般的にはGZIPの利用がすすめられるとのこと。
超難読化 (スコア:3)
「GZIPのほうが圧縮率が高くなる」のは当たりまえ (スコア:2)
PNGの可逆圧縮は、
画像専用アルゴリズムとしての特殊なことは基本的にほとんど何もせず、
ビットマップデータを、gzipと同じdeflateで圧縮するだけのものです。
(PNG独自な画像ベースの圧縮処理として、deflateをかける前に、上や左の画素との差分を取っておくフィルタ処理もありますがが、差分を取るかどうかは自由(圧縮プログラムが、より圧縮しやすい方を選べばいい)で、プログラムコードを画像にマップした場合、このフィルタ処理は有効とは思えないので、単なるdeflate圧縮になっていると思います)
そういうものですので「余計なPNGとしてのヘッダ情報」を付加する必要がない分、
「GZIPのほうが圧縮率が高くなる」のは当たりまえですね。
むしろ「gzipとほぼ同等の圧縮率が実現できる」とアピールしてもいいんじゃないかなぁ。
Re: (スコア:0)
そこでWebP losslessですよ。試したところ、gzよりも小さくなってます。
Re: (スコア:0)
おっしゃるとおりです
しかし,差分を取るフィルタ処理がたまたまうまく寄与する場合も,可能性としてはありえます.
例えば,画像情報を配列で内部に持っているjavascriptであれば,データとしてはほぼ画像データになりますので
画像専用のアルゴリズムのほうが有利になりえます
ですから「GZIPのほうが圧縮率が高くなる」のは多くの場合正しいですが,「当たりまえ」ではありません
ここまで考えると,タレコミ文にある「ただし多くの場合GZIPのほうが圧縮率が高くなる」という表現のほうが適切になると思います.
何故今更? (スコア:2, 参考になる)
幾ら速報サイトではないとはいえ、7年前の再発明を記事にしなくても…。
と思ったんですが、コメント見る限り知らない人が多そうですね。
Web系のsraderなら8割位知っているはずの有名な話だと思ったのですが。
最初は2008年のこのブログ(404) [nihilogic.dk]で公開されたテクニックです。
日本だと2010年のJavaScriptとCSSをPNGファイルに含めて圧縮する方法 [mynavi.jp]で最初に紹介されました。
当時はかなり話題になって、、、
スゲー、JS超圧縮できるじゃん!
いや、普通にApacheでgzipしろよ…
PNGヘッダーの分、サイズ増えてるだろ!
バカ言うなやる事に意味があるんだ!!
いや、ちょっとまて、flickrやフォト蔵をjs置き場に出来るって事じゃないか!?
天才現る!
いや、普通にサービス規約的にダメだろ
いや、ちょっとまて、pngって事はdataURIでもOKって事じゃね?
HTMLにJSが埋め込めるぞ!あれ?
頭大丈夫?
いや、ちょっとまて、転送URLにdataURIぶち込めばいんじゃね?
本物の天才現る!
いや、普通にサービス規約的にダメだろ
と言うか、これcanvas使ってるからIEだめじゃね?
あ…
って、感じの事がありました。で、IEがcanvasに対応した時にに再燃して、
もしかして、JSをpngに圧縮する技術の時代が来たんじゃね?
それだ!
PNG最高!
スゲー、JS超圧縮できるじゃん!IEでもちゃんと動くよ!
いや、普通にnginxでgzipしろよ…
今更言うなよ!もうrailsのプラグイン書いちゃっただろ!!
いや、ちょっとまて、flickrやフォト蔵をjs置き場に出来るって事じゃないか!?
そういうのもう終わってるから。
いや、ちょっとまて、これ究極の難読化じゃね?
よし!お前はまずevalの前にブレークを入れる作業に入るんだ
まあ、evalの前、覗かれたらPacker [edwards.name]でも同じだしな。
普通にClosure Compilerの最適化MAXで良いだろ。
いや、あんな気持ち悪いルールでコード書きたくないし。
で、結論は?
使えねぇ
って、感じの2周目もありました。因みにやってみると分かりますが、
圧縮側もjsの解凍側も凄く簡単に実装できるのでネット中に実装あふれてます。
休日の暇つぶしにちょうど良い位のボリュームなので、実装してみると楽しいですよ。
今更たまたま実装した個人がまた出たってだけでストーリーになるのが意外でした。
メガデモに使うって言うのも海外のサイトではありましたし。
そもそも、sradで一度も取り上げられてなかったのが意外ですね。
コメント欄とか日記とかまで探せば取り上げられてそうな気はしますが。
Re: (スコア:0)
おっさんの昔話が始まったぞ。
すっごく長くなるからみんな覚悟しろ!
用途とか (スコア:1)
ほなこれいらんやん。
#思いついたら作ってしまう、作ったら公開してしまう。アレゲなる人情に称賛。
Re:用途とか (スコア:1)
GZIPの展開処理を付け加えるとプログラムが肥大化するので
ありあわせのPNGデコーダでなんとかしたかったのでは?
Re:用途とか (スコア:1)
メガデモ用途ですよ。
スクリプトを圧縮した結果であるPNG画像自体もテクスチャとかカオティックなノイズ源とかとして使い回すんでしょう。
Re:用途とか (スコア:1)
・ローカルにファイルとして存在しているものを使う
→Accept-Encoding使えないのでgzip使えない
加えて、この手法は自己解凍機能を持ってます。
文字通り自己解凍です。このpngファイル1つで完結できます。いやマジで。
Re:用途とか (スコア:1)
>文字通り自己解凍です。このpngファイル1つで完結できます。いやマジで。
なるほど、そういう世界だったのか。
#電脳世界は広大だ。でもこの話はlocal限定っぽいけど。
Re: (スコア:0)
PNGに偽装しといて自己展開とかエンコード方法の部分より遥かにアレゲな要素ですね。
コード部をテクスチャとして使う以外にもテクスチャを普通に後ろに添付できそうだ。
自己展開の言語もJSなら頭のマジックはどう処分するんだろう……?
Re: (スコア:0)
雑誌でソースコード配布するさいにQRコード見たいに読み取ればタイプミスでエラーとかなくせるんじゃね?
#ネットで配布した方が早いとかいわない!
Re: (スコア:0)
見たいに
Re: (スコア:0)
プログラムを圧縮した結果が絵になるように工夫して、プログラム中で自身を画像として読み込んで加工するんでしょ。
メガデモってデータ込み500KBでOpenGL使うようなやつだよ
デモシーン=メガデモ (スコア:0)
「メガデモ」が懐かしすぎる。昔から謎技術で圧縮重視、計算によるシーンの構築だったな。
キャッシュ (スコア:0)
これってキャッシュはしてくれるのかな?
できればローカルで展開してくれた形でキャッシュされてほしい(無理だろうけど)
Re: (スコア:0)
ブラウザからみたら単なるファイルなんでキャッシュするでしょう。
#一般的ヘッダなら
展開した形でキャッシュしたいならWeb Storage使えばいいんじゃね?
#でもメガデモじゃ不必要だけど。つかgzip使えっつーことに。
これ大丈夫かな (スコア:0)
PNG偽装のスクリプト上げられるって
中々に穴が開きそうな気がするんですが
JavascriptでPNGからスクリプト抽出&実行できる環境に
アップローダーの組み合わせみたいな
アップロードディレクトリを
public_htmlの外においている安全策も
PHPには有効でしょうけど
クライアントで実行されるスクリプトには無力なような
デモサイトを自前で公開する方は
よく考えて実装したほうがよさげ
Re:これ大丈夫かな (スコア:2)
> PNG偽装のスクリプト上げられるって
> 中々に穴が開きそうな気がするんですが
いや、もう穴自体はあいてますよ。
ていうか、JavaScriptコードがエンコードされたファイルはあくまで画像ファイルですので、そこからJavaScriptコードの抽出処理を行わなければまったくの無害です。
問題は、どうやってコード抽出処理を行うか。
ストーリーのリンク先で説明されていますが、このJS圧縮PNGは、自己展開実行機能を持たせることも可能としています。その原理は、
・IEはContent-Typeを無視し、データの中身を見てファイル種別を判断する
・そのためPNGのヘッダ情報に(コメントデータとして)HTMLのタグっぽいものを埋め込んでおくと、HTMLデータと誤認する
・そこで、PNGのヘッダに、HTMLとして「画像変換されたコードを抽出実行するJavaScriptコード」を埋めこんでおくと、
・画像のURLを直接ブラウザで開くと、HTMLと解釈されて抽出コードが稼働し、画像化されたコードも実行される
という流れ。この前半部分、最初に展開コードの実行をキックする流れ自体は、「JSをPNGに変換する部分」とは無関係な技です。
つまり、今回のネタとは関係なく、「画像ファイルをアップロードできるアップローダ」で、「アップロードしたそのまま生の画像」を「(imgタグ経由ではなく)URL指定でブラウザから直接開くことができる」場合、
余所のサイトから、 a href="画像URL"> といった画像直リンクを踏ませることで、
スクリプトインジェクションが可能になる、ということです。
インジェクションさせないためには、アップローダとして、
・画像アップローダでは、(拡張子偽装がされていないかどうか)実データの形式チェック
は必須ですが、それに加えて、
・ファイルのブラウザ直接表示はさせない(Content-Dispositionなどのヘッダを付けて、ダウンロードさせる)
・画像は、アップロードしたファイルそのままではなく、不要なヘッダは捨てるフィルタ処理を行う
・REFERチェックなどで、画像直リンクは許さない
などといった対策は必要でしょう。
#一番のガンは、Content-Typeを無視するIEですが…
Re: (スコア:0)
Macで開発してるっぽいのに、なんでIEの話が出てくるん?
Re:これ大丈夫かな (スコア:1)
すみません、自己展開処理については説明を誤読してました。
JavaScriptコードを埋め込んだPNGファイルを、拡張子 html にして(Content-Type: text/html にして)、ブラウザに送り込んでますね。
これなら、IEに限らずブラウザ汎用で動作します。
でも、元コメの「穴があくんじゃないのか」という疑問に対しては、
画像として特殊なことはしてませんので、だからどうしたということは特になく、
そもそも「HTMLデータを送りこめてる」時点で大穴、ということになります。
Re: (スコア:0)
気になるのは、これが PNG だからという理由でセキュリティソフトのチェックをすり抜けるかどうかです。
Re: (スコア:0)
>ストーリーのリンク先で説明されていますが
IEの話なんてどこに書いてあるんです?
Re:これ大丈夫かな (スコア:1)
確かに、リンク先の説明はブラウザ汎用っぽい文章になっており、IEの話なんて書かれてないんですが、実際のところそれが動作するのはIEだけです。
それ以外のブラウザ(少なくともFirefoxとChromeとOperaとSafari)は、ちゃんとContent-Typeを見て動作しますので、Content-Typeを画像と偽装したHTMLデータがHTMLとしてレンダリングされることはありません。
Re: (スコア:0)
いや、リンク先のデモ画像もMacのブラウザ(絶対IEではない)だろ...
IE憎しで頭おかしくなってないか?
Re:これ大丈夫かな (スコア:1)
すみません、確かにIE憎しが念頭にありました。
#2814116 [srad.jp]に書いた通りで、拡張子をhtmlに変えてしまえばMacでも何でも動作します。
元コメの「穴が空いてるかどうか」については、「IEなら元から空いている」「IE以外なら大丈夫」ってことで。
Re: (スコア:0)
どうしてもIEに穴があることにしたいようですが、
いまやContent-Typeが無視されないようにするのはサイト管理者側の責任ですよ。
# 互換性のためとはいえ、デフォルトが危険な状態なのは如何なものかとは思うけど。
https://www.google.co.jp/search?q=x-content-type-options+nosniff [google.co.jp]
Re: (スコア:0)
どうもPNGバイナリ中に任意文字列として埋めたHTMLとその中のスクリプトで起動するようなので、アップロードされたファイルをHTMLとして解釈されなければ大丈夫だと思います。
……そういえば、コンテントタイプ無視してHTMLっぽければHTMLとして解釈するWebブラウザも居ましたね。
強制圧縮プロキシ (スコア:0)
モバイル環境等で,強制的に画像の再圧縮をかけるようなプロキシが
設置されていた場合には,どういったことが起こるんだろうか?
Re: (スコア:0)
メガデモ用ソリューションで、htmlファイルとしてローカルに置く想定。
サーバに置いても動くかわからない。
もし動くとしてもhtmlとしておくので再圧縮はかけない。
もし再圧縮かけるクソ仕様なら動かない。バグる。
JPEGなら・・・ (スコア:0)
さらに1/10くらいになる?
Re: (スコア:0)
JPEGは不可逆圧縮だから、元のスクリプトに戻せないんじゃないの?
ロスレスな圧縮もできるだろうけれど、その場合は大した圧縮率ではないですし。