ソーシャルメディアフィンガープリントとその対策

(Last Updated On: )

ソーシャルメディアフィンガープリントがまた話題になっているようです。ソーシャルメディアフィンガープリントとは何か?およびその対策です。

ソーシャルメディアに限らず、ログインをサポートしているサイトであれば、全て対象です。

ソーシャルメディアフィンガープリントとは?

コンピューターセキュリティーに於けるフィンガープリントとは、利用しているシステム(OS)やサービス(WebやDBサーバーなど)をプロトコルやアプリケーションの特徴や動作から利用しているシステムやサービスを判別する仕組みです。ネットワークサービスなどを検出するNMAPはOSのフィンガープリント検出をサポートしています。Webサーバーやデータベースサーバーのフィンガープリントを検出など、様々な方法が考案されています。 1

ソーシャルメディアフィンガープリントとはWebサイトにログインしているか?していないか?を第三者が検出する手法です。ソーシャルメディアに限らず、サイトにログインしているか、していないか、を第三者が検出できることは以前2から広く知られています。次のサイトがデモサイトとして公開されています。このデモサイトが最近公開されたのでまた話題になっているようです。

https://robinlinus.github.io/socialmedia-leak/

この問題はソーシャルメディアに限ったことではないので、ログインフィンガープリントとした方が良いように思いますが、名前のインパクト的には「ソーシャルメディア」が付いている方がキャッチーですね。

ソースコードがGitHubで公開されているので、ソースコードを参照できます。

検出の仕組みは簡単です。ログイン前とログイン後では異る動作をするイメージファイルなど3でログイン済みかどうか判別します。例えば、https://github.com/RobinLinus/socialmedia-leak/blob/master/demo.jsからは以下のURLでログインのしているかどうか、判別できることが解ります。

https://twitter.com/login?redirect_after_login=%2Ffavicon.ico

以下のようにするとicoイメージファイルはログイン時にはonloadハンドラーが呼ばれ、ログインしていない時にはonerrorハンドラー呼ばれます。

<img onload="alert('logged in to twitter')" 
onerror="alert('not logged in to twitter')" 
src="https://twitter.com/login?redirect_after_login=%2Ffavicon.ico">

このHTML+JavaScriptファイルをtest.htmlなどして、Webサーバーなどで参照するとログインしているか、していないか判別できます。PHPのビルトインWebサーバーなら、test.htmlが保存してあるディレクトリで

php -S 127.0.0.1:8888

として

http://127.0.0.1:8888/test.html

とアクセスするとalertダイアログボックスでlogged in to twitterかnot logged in to twitterのどちらかが表示されます。

ログインしているとリダイレクトされICOの画像が取得できOK(onload)、ログインしていないとICO画像でなくログインページが返されNG(onerror)になることが判別できる理由です。

 

ログインフィンガープリント対策

サイト運営者側の対策

  • ログインしている時としていない時に違う結果を返すイメージやJavaScriptファイルやプログラム(サンプルコードにあるURLリダイレクター付きログインページなど)を置かない
  • 取り除けない場合にはCSRFトークンのようなトークンを付ける
  • 必要無いならログイン後のリダイレクターなどは実装しない(ログインをサポートする場合、これは難しい)

リダイレクト先のブラックリストを作って対策しようとしても無理があります。簡単に別のファイルを作ってしまい、簡単に見つけられてしまいます。もしするなら、.htmlや.php(MIMEメディアタイプに注意)など安全なファイルのみに限定します。拡張子で決るなら拡張子で良いでしょう。拡張子で決まらない場合、リダイレクト先のファイルタイプ(MIMEメディアタイプ)をチェックして、onloadとonerrorをサポートしない、確実に安全なリダイレクト先4であることを入力バリデーション処理として実装するなどの方法が考えられます。ログインなどの処理の先にチェックする必要があります。

リダイレクト先が自由に設定できない様にする方法も利用可能です。セッション変数($_SESSION)なら簡単にリダイレクト先を保存できますが、複数タブ/ブラウザ/デバイスから同じセッションIDでログインしている場合にはレースコンディションの可能性があります。直近10くらいまでのリダイレクト先のハッシュ値(ソルト付き)をリダイレクト先の識別子として利用する、といった工夫が必要です。

リダイレクト先の識別子(識別子削除処理は省略)

<?php
//リダイレクト先のID作成
$redir_id = sha1('/path/to/file'.'some_random_salt');
$_SESSION[$redir_id] = '/path/to/file';
?>
<?php
//リダイレクト付きログインURL
$login_url = 'http://example.com/login.php?redir='.rawurlencode($redir_id);
?>
<?php
//リダイレクト
$redir_id = sha1($_GET['redir'].'some_random_salt');
if (!empty($_SESSION[$redir_id])) {
  header('Location: http://example.com/'.$_SESSION[$redir_id]);
  exit;
}
?>

 

古いPHPでは使ってはいけません5が、CSRFの様なトークンを付けるにはoutput_add_rewrite_var関数が便利です。

トークンを作って付与する例

<?php
ob_start();
session_start();
$token = hash('sha2', session_id());
// URLリライターを使って、http://example.com/favicon.icoなどを
// http://example.com/favicon.ico?tk=XXXXXXXXXXXXに書き換える
output_add_rewrite_var('tk', $token);
?>

言うまでもありませんが、.icoや.jpgにトークンを付けた場合、これらのファイルのPHPスクリプトとして処理できるようにしなければなりません。パフォーマンスには注意してください。

トークンをチェックする例

<?php
ob_start();
session_start();

$token  = hash('sha2', session_id());
$utoken = $_SERVER['REQUEST_METHOD'] == 'GET') ? $_GET['tk'] : $_POST['tk'];

// タイミング攻撃防止の為に、hash_equals()の利用は必須
if (!hash_equals($token, $utoken)) {
  die('Go away');
}
?>

セッションIDは定期的(少なくとも1時間に一回くらいは更新したい)に更新すべきなので、実際に利用する場合にはもう少しコードが必要です。これらのトークン類はセッションIDと同じように定期的に変更すべきです。$_SESSIONに保存した固定のトークンなどは使わないようにしましょう。

最近ではクライアント(JavaScript)でリクエストURLを作る場合も多いので、その場合はトークンを取得するAPIをサーバーに作ると良いです。JavaScriptからセッションIDのクッキーにアクセスはできない様にすべき(HttpOnly属性を設定する)なので、サーバーサイドと同じようにセッションIDから生成する手法は取るべきではありません。

 

利用者側の対策

  • プライベートブラウズを利用する
  • 別のプロファイルを利用する(SNSサイトなどにログインしないこと!)
  • 別のブラウザを利用する(SNSサイトなどにログインしないこと!)
  • プラグインを利用する(上記のサイトではPrivacy BadgeruMatrixなどを例示)
  • 3rdパーティークッキーを無効化する

参考:ソフトウェア開発環境のセキュリティ対策

どのソーシャルメディアを使っているかどうかはプライバシーの問題ですが、利用中のソーシャルメディアが分かればターゲットを絞ったソーシャルエンジニアリング攻撃が行いやすくなります。

3rdパーティークッキーはHEISTと呼ばれるSSL/TLSのサイドチャネル攻撃(圧縮を利用する物)もあり、無効にする方が安全[^note-heist]です。

[^note-heist] 3rdパーティクッキーを有効にしていると、SSL/TLSを使っていてもセッションIDが盗める場合があります。BEAST、CRIMEで圧縮は無効にしていると思いますが、サイト運営者は”圧縮を使わない”ようにしましょう。念の為、セッションIDは頻繁に更新しましょう。

 

まとめ

大きなサイト以外では対応する必要性が少ないですが、こういう方法もあり、ターゲットを絞った攻撃には利用可能であることを知っておくと良いと思います。

普通のサイト、普通のユーザーにとってはオマケで紹介したHEISTの方が問題です。セッションIDを盗まれます。サイト運営者の方はSSL/TLSでは圧縮を使わないようにしましょう。[^note-heist-attack] この種の攻撃はセッションを正しく管理[^session]することによりかなり緩和できます。

[^note-heist-attack] 攻撃には、そもそもの暗号化済みの通信はどうやって取得するの?という課題がありますが、これは罠のWiFiアクセスポイントとかARPスプーフィングなどが利用できます。

[^session] 正しいセッション管理はまだまともに書いたことがないです。間違いだらけのセッション管理とその対策にポイントは記載しています。


  1. 変わり種としては「文章の特徴から著者を特定する」フィンガープリントも存在します。 
  2.  http://www.tomanthony.co.uk/blog/detect-visitor-social-networks/ フィンガープリントの検出手法はこれよりも前から知られている。 
  3.  JavaScriptなど、ログイン前後でtrue/falseと判定できるものならOK。 
  4. text/htmlやtext/plain 
  5. 理由はまだこのブログにも書いていません。問題が発覚して数年、私がパッチを作って1年以上たった最近のPHPで修正しています。 

投稿者: yohgaki