signed_requestの署名を確認する

昨日、iframe版Facebookページで、「いいね」されているかどうかで表示を切り替える方法を解説しました。
ただ、「いいね」されているかどうかで、セキュリティ的に重要な情報を表示するかどうかを切り替える場合、signed_requestが本当にFacebookから送られてきたものかどうかをチェックすることが必要です。
今日はその方法を解説します。

1.signed_requestの署名

昨日のサンプルは、signed_requestの文字列を、単純にデコードするだけでした。
ただ、その方法だと、Facebookを装ったデータをPHP等に送りつけられると、「いいね」されているときのページを盗み見されてしまうという問題があります。
そこで、signed_requestの文字列が、本当にFacebookから送られたものかどうかを調べるようにします。

signed_requestは、以下の2つの値をピリオド(.)でつないだ文字列になっています。

  • HMAC SHA-256で署名した文字列
  • アプリに関する情報を含むJSONオブジェクトをBASE64URLでエンコードした文字列

署名には、アプリケーションの秘密鍵が使われます。
秘密鍵は、Facebookと、アプリケーションの作者(=あなた)だけが知っている情報です。
したがって、この署名を確認することで、signed_requestが本当にFacebookから送られてきたものかどうかを確認することができます。

なお、アプリの秘密鍵は、「マイアプリ」のページでアプリケーションを選んだときに表示されるページで、「アプリの秘訣」の箇所に表示されます。
また、秘密鍵は、他人には絶対に知られてはなりません(知られてしまうと、Facebookを装って、その秘密鍵で署名したデータを送りつけられることがありうるので)。

アプリケーションの秘密鍵

2.署名を検証する関数

Facebookの「Signed Request」の解説のページの「Verifying and Decoding」の項に、署名を検証した上でデータをデコードする関数のコードがあります(parse_signed_request関数とbase64_url_decode関数)。
これらの関数のコードをコピーして、自分のiframe版FacebookページのPHPに張り付けて使うと良いです。
また、iframe版Facebookページを多数作るなら、コードを独立したPHPファイルにして、個々のPHPにinclude文で組み込むと良いでしょう。

たとえば、関数のコードを「signed_request.php」というPHPファイルに入れたとします。
この場合、iframe版Facebookページのひな形のコードは、以下のようになります。
なお、3行目の「あなたのアプリケーションの秘密鍵」のところは、実際の秘密鍵に置き換えます。

<?php
include('signed_request.php');
if (isset($_POST['signed_request'])) {
    $data = parse_signed_request($_POST['signed_request'], 'あなたのアプリケーションの秘密鍵');
}
?>
<html>
<meta charset="UTF-8">
<title></title>
</html>
<body style="margin : 0; padding : 0;">
<div style="width : 520px; overflow : hidden;">
<?php if ($data && $data['page']['liked']) : ?>
    「いいね」されているときに出力する内容
<?php else : ?>
    「いいね」されていないときに出力する内容
<?php endif; ?>
</div>
</body>
</html>