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

pblog

pplog.net を作っている @ppworks こと越川直人(Koshikawa Naoto)のブログ。esa LLCで働いてます(\\( ⁰⊖⁰)/)

署名付きリクエストで外部サーバへデータを保存する

javascript OpenSocial mixiアプリ

今までアプリケーションのデータ保存は永続化データに任せていました。この度、mixiアプリを作成しましたで作成したアプリを機能拡張するにあたり、データを外部サーバに保存してみようと思います。あるユーザの投稿内容を外部サーバへ送る際に気をつけなければ行けないことを調査してみました。


結論からいうと、署名付きの

gadgets.io.makeRequest

を使うようにする、ということになります。

今回はその具体的な使い方を見ていきます。
その前に、OpenSocialアプリケーションとOpenSocialコンテナ、外部サーバの関係について整理しておきます。

f:id:naoto5959:20090526204332p:image

署名なしのgadgets.io.makeRequestからのリクエストを確認する

まずは署名なしのgadgets.io.makeRequestを使ったリクエストはサーバ側へ、どのようなパラメータを渡すのかを確認します。

外部サーバに配置するAPI

以下のようなコードをPHPで記述するとします。(以降api.phpと呼びます。)受け取ったGETパラメータ、POSTパラメータを表示するだけの単純なコードです。

<dl>
<dt>GET</dt>
<dd><dl>
<?php
// api.php
foreach ($_GET as $key => $value) {
  print "<dt>$key</dt><dd>$value</dd>";
}
?>
</dl></dd>
<dt>POST</dt>
<dd><dl>
<?php
foreach ($_POST as $key => $value) {
	print "<dt>$key</dt><dd>$value</dd>";
}
?>
</dl></dd>
</dl>

Gadget XML

gadgets.io.makeRequest関数を使って、api.php

  • GET
    • param1 = value1
  • POST
    • param2 = value2

を渡してみます。

<Module>
  <ModulePrefs title="make request test" author="naoto koshikawa">
    <Require feature="opensocial-0.8" />
  </ModulePrefs>
  <Content type="html">
  <![CDATA[
    <script type="text/javascript" src="<PathTo>/jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
    var callback = function(res) {
      $('#result').html(res.text);
    };
    var url = "<PathTo>/api.php?param1=value1";
    var postData = {param2: "value2"};
    var params = {};
    params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = 0;
    params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
    params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(postData);
    gadgets.io.makeRequest(url, callback, params);
    </script>
    <p id="result" style="font-size:12px">
    result
    </p>
  ]]>
  </Content>
</Module>
渡ったパラメータを確認

結果、ブラウザには以下のような結果が表示されます。
f:id:naoto5959:20090526204331j:image
GET、POSTで渡したパラメータが渡っていることが分かります。

署名付きのgadgets.io.makeRequestからのリクエストを確認する

次に、署名付きのリクエストを見てみましょう。

外部サーバに配置するAPI

まずは先ほどと同じもので試します。

Gadget XML

先ほどと同様に、gadgets.io.makeRequest関数を使って、api.php

  • GET
    • param1 = value1
  • POST
    • param2 = value2

を渡してみます。今回は署名付きのリクエストとするため

params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;

の部分を追加していることがポイントです。

<Module>
  <ModulePrefs title="make request test" author="naoto koshikawa">
    <Require feature="opensocial-0.8" />
  </ModulePrefs>
  <Content type="html">
  <![CDATA[
    <script type="text/javascript" src="<PathTo>/jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
    var callback = function(res) {
      $('#result').html(res.text);
    };
    var url = "<PathTo>/api.php?param1=value1";
    var postData = {param2: "value2"};
    var params = {};
    params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = 0;
    params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
    params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(postData);
    // 以下を追加しましたよ
    params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;
    gadgets.io.makeRequest(url, callback, params);
    </script>
    <p id="result" style="font-size:12px">
    result
    </p>
  ]]>
  </Content>
</Module>
渡ったパラメータを確認

結果、ブラウザには以下のような結果が表示されます。
f:id:naoto5959:20090526204330j:image
GET、POSTで渡したパラメータ以外にもパラメータが渡っていることが分かります。
自分で渡した覚えのないパラメータも渡っていますね。これらのパラメータを使い、署名を確認します。署名の確認方法は以下を参考にしました。

mixi Developer Center (ミクシィ デベロッパーセンター) » 署名付きリクエストの検証:
http://developer.mixi.co.jp/appli/make_request/validating_signed_requests

署名を確認する。

署名を確認するコードをapi.phpに追加してみます。今回は、署名が正しい場合に受け取ったGET、POSTパラメータを表示します。
実際には、

といった値を元に、POSTで渡したパラメータを記録するなどを行うことになると思います。

<?php
require_once "OAuth/OAuth.php";

class MixiSignatureMethod extends OAuthSignatureMethod_RSA_SHA1 {
  protected function fetch_public_cert(&$request) {
  return <<< EOD
-----BEGIN CERTIFICATE-----
MIICdzCCAeCgAwIBAgIJAOi/chE0MhufMA0GCSqGSIb3DQEBBQUAMDIxCzAJBgNV
BAYTAkpQMREwDwYDVQQKEwhtaXhpIEluYzEQMA4GA1UEAxMHbWl4aS5qcDAeFw0w
OTA0MjgwNzAyMTVaFw0xMDA0MjgwNzAyMTVaMDIxCzAJBgNVBAYTAkpQMREwDwYD
VQQKEwhtaXhpIEluYzEQMA4GA1UEAxMHbWl4aS5qcDCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAwEj53VlQcv1WHvfWlTP+T1lXUg91W+bgJSuHAD89PdVf9Ujn
i92EkbjqaLDzA43+U5ULlK/05jROnGwFBVdISxULgevSpiTfgbfCcKbRW7hXrTSm
jFREp7YOvflT3rr7qqNvjm+3XE157zcU33SXMIGvX1uQH/Y4fNpEE1pmX+UCAwEA
AaOBlDCBkTAdBgNVHQ4EFgQUn2ewbtnBTjv6CpeT37jrBNF/h6gwYgYDVR0jBFsw
WYAUn2ewbtnBTjv6CpeT37jrBNF/h6ihNqQ0MDIxCzAJBgNVBAYTAkpQMREwDwYD
VQQKEwhtaXhpIEluYzEQMA4GA1UEAxMHbWl4aS5qcIIJAOi/chE0MhufMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAR7v8eaCaiB5xFVf9k9jOYPjCSQIJ
58nLY869OeNXWWIQ17Tkprcf8ipxsoHj0Z7hJl/nVkSWgGj/bJLTVT9DrcEd6gLa
H5TbGftATZCAJ8QJa3X2omCdB29qqyjz4F6QyTi930qekawPBLlWXuiP3oRNbiow
nOLWEi16qH9WuBs=
-----END CERTIFICATE-----
EOD;
  }
}

$request = OAuthRequest::from_request(null, null, array_merge($_GET, $_POST));

//Initialize the new signature method
$signature_method = new MixiSignatureMethod();

//Check the request signature
@$signature_valid = $signature_method->check_signature($request, null, null, $_GET["oauth_signature"]);

//Build the output object
$payload = array();
if ($signature_valid == true) {
  // 署名が正しい場合の処理
  /*
    以下のGETパラメータを用いて、owner id, viewer id, application idを特定し何か処理を行う。
    $_GET["opensocial_owner_id"];
    $_GET["opensocial_viewer_id"];
    $_GET["opensocial_app_id"];
   */
} else {
  // 署名が正しくない場合の処理
  exit;
}
?>
<dl>
<dt>GET</dt>
<dd><dl>
<?php
// cool.php
foreach ($_GET as $key => $value) {
	print "<dt>$key</dt><dd>$value</dd>";
}
?>
</dl></dd>
<dt>POST</dt>
<dd><dl>
<?php
foreach ($_POST as $key => $value) {
	print "<dt>$key</dt><dd>$value</dd>";
}
?>
</dl></dd>
</dl>

まとめ

署名付きリクエストで安心して外部サーバへデータを保存出来そうです。
んが、そもそも署名ってなんだろう。ということで以下の記事が参考になります。

Tender Surrender » OAuthの署名方式を掘り下げる:
http://devlog.agektmr.com/ja/archives/174

Tender Surrender » OpenSocialのOAuthまとめ:
http://devlog.agektmr.com/ja/archives/79