読者です 読者をやめる 読者になる 読者になる

clock-up-blog

go-mi-tech

Zaif のセッション情報が盗まれた原因のひとつについて。JavaScript からクッキー値を取得させない方法。

セキュリティ JavaScript

HTTP Headers という 5万人が使っている Chrome 拡張のマルウェア疑惑。セッション盗まれて BTC も盗まれそうになった話。 の続き。

今回は Chrome 拡張とは関係ない、サイト設計側の話です。

※本記事では Zaif のセキュリティ上の問題について指摘していますが、非難の意図はありません。

続報:11月4日

Facebookコメントより。

Ryosuke Hosoi · テックビューロ CTO
ご指摘ありがとうございました!少し事情があってすぐに対応出来なかったのですが、先ほどZaifの認証情報にもhttp_only属性がつくようになりました。
しかしながら、jsが汚染されていると他にもいろいろ攻撃出来てしまいますので、今回の件はこれでもう安心、というわけではないと考えています。
15時間前

11月14日時点で httponly 属性が付くようになったようです。対応お疲れ様です。

コメントにもある通り、jsが汚染されてる時点でいろいろあかんので問題の根幹はあくまでも拡張機能(今回は HTTP Headers)側にあることを改めて強調しておきます。

Facebook にていただいた情報

Facebookの仮想通貨勉強会グループ にて情報をいただきました。

2016/11/3 13:28 Jonathan Underwood (bitbank株式会社 技術顧問)

httponly及びsecureのクッキー属性に対応しましょう。

zaifの場合はsecure対応でhttponly未対応だったのでjsからセッションクッキー抜き盗られて乗っ取られたんです。

運よくzaifが出金を止めたんですが。。。

なるほど。クッキー属性として httponly が付いていなかったため、JavaScript の document.cookie というシンプルなアクセス手段で大事なクッキーデータが抜き出された可能性がある、とのこと。

実際にクッキーを見てみる

Zaif にログインした状態で Chrome の Developer Tools にて、Application タブからクッキー内容を確認してみます。
f:id:kobake:20161104040603p:plain
開発用ツールからの閲覧なのでクッキー値が全部見れることは一向に構わないのですが、「HTTP」というフィールド値がすべて空っぽになっていることに注目です。ここが空っぽの場合、これらのクッキー値は JavaScript から直接アクセスが可能です。

そしてこれらのクッキー名を見る限り、セッション系のデータがもりもり詰まっていそうです。これらが盗まれたら何かやばそう。

※追記(11月5日):現時点では Zaif 側の対応が完了しており、httponly 属性が付くようになっていることを確認しました(11月4日時点で対応が行われたようです)

JavaScript からクッキー情報を取得してみる

Chrome の Developer Tools Console にて、document.cookie を表示してみます。
f:id:kobake:20161104041316p:plain
さきほど Application タブで確認したすべてのクッキー値が全てそのまま取得できてしまっていることが確認できます。

このような状態になっている場合、前記事 で示したケースのような任意JavaScriptが実行され得ることを想定すると、クッキー値がまるまる盗まれる恐れがあります。

ここは推測

Zaif へのログイン中に、前記事 で示したような不正な Chrome 拡張 の JavaScript によりクッキー値(セッション情報含む)がまるまる盗まれた可能性があります。あくまでも可能性に過ぎませんが。

サイト側でできる(クッキー面での)対策

クッキー属性として、 httponly という属性があります。この属性が付いたクッキー値は JavaScript から読み取り不能になります。

そもそも 前記事 のように任意JavaScriptが実行されうる窮地に陥った時点で限りなくアウト(サイト側の責任ではない)なのですが、それでもなお、せめてクッキー値くらいは守る手段として、セキュアに扱いたいクッキー値には httponly 属性を付けておくのが無難でしょう。

サンプルPHP

httponly 付けない版 (JavaScriptから該当クッキー見える)

<?php
// クッキー値をインクリメント
$not_httponly_data = $_COOKIE['not_httponly_data'];
if(!$not_httponly_data)$not_httponly_data = 0;
$not_httponly_data++;

// httponly は付けない版 (JavaScript からクッキー値見える版)
setcookie('not_httponly_data', $not_httponly_data, 0, '', '', false, false);
?>

<p>
    PHP から取得した値<br/>
    not_httponly_data = <?php echo($not_httponly_data); ?>
</p>

<!-- JavaScriptから取得できるクッキー値の表示 -->
<div>JavaScript から取得した値</div>
<div style="width: 300px; height: 100px; border: 1px solid #ccc; padding: 4px;">
    <script>
        document.write(document.cookie.replace(/</g, '&lt;'));
    </script>
</div>

httponly 付けた版 (JavaScriptから該当クッキー見えない)

<?php
// クッキー値をインクリメント
$httponly_data = $_COOKIE['httponly_data'];
if(!$httponly_data)$httponly_data = 0;
$httponly_data++;

// httponly を付ける版 (JavaScript からクッキー値見えなくなる版)
setcookie('httponly_data', $httponly_data, 0, '', '', false, true);
?>

<p>
    PHP から取得した値<br/>
    httponly_data = <?php echo($httponly_data); ?>
</p>

<!-- JavaScriptから取得できるクッキー値の表示 -->
<div>JavaScript から取得した値</div>
<div style="width: 300px; height: 100px; border: 1px solid #ccc; padding: 4px;">
    <script>
        document.write(document.cookie.replace(/</g, '&lt;'));
    </script>
</div>

両サンプルを実行した後のクッキー状態

今回は httponly_data という名前のクッキーに対して httponly 属性を付けました。
Chrome Developer Tools の Application タブでクッキーを確認してみます。
f:id:kobake:20161104060255p:plain:w600
httponly_data の http フィールド値部分にチェックマークが付いたことが確認できます。
このようにチェックマークの付いたクッキー値は JavaScript から取得することができません。

クッキーを守る意味

クッキーさえ守れれば全てOK、というわけではありませんが、対策のひとつとして大事なクッキーを JavaScript からアクセスさせないために httponly 属性を付けておくことは、今後の(治安の悪くなりそうな)インターネット上のサイトにおいてはひとつの防衛策として有効かと思います。

そもそも任意JavaScriptが呼ばれる状況というのが普通はありえない(と思っていた)のですが、仮にそういう状況になってしまった場合、せめてもの最後のあがきとしてクッキー保護していただけたら、被害はゼロにならないとしても、少なく抑えられるとは思います。

防波堤はいくつもあったほうが良いのです。(防波堤を構築するコストもまた無視することはできないのですが)

Zaif のセキュリティについて

任意スクリプトが実行されてしまうような(自己責任な)状態が発生してしまった場合、クッキーが盗まれ得る問題は見つかりましたが、そもそも Zaif には二段階認証の機能があるので、ちゃんとこれ設定しとけば不正送金とかは防げると思います。僕は愚かにもこれ設定してなかったんです。反省。(今回懲りてすぐに設定した)

});