AmazonアソシエイトWebサービスの名称変更に伴う署名認証(Perl)
Amazonアソシエイトで、Webサービスを利用している方々のホットな話題です。
いや〜、参りました。
突如メールが届いて、簡単に言えば「3ヶ月の猶予期間をあげるから、その間にAWSを使っているアプリの仕様変更をして下さい」とのことです。
仕様変更の内容はというと、リクエスト日時をTimestampパラメータに含めることと、シークレット・アクセス・キーを使って「RFC2104 HMAC-SHA256」で署名ハッシュを作ってリクエストに追加するというもの。
いや〜、参りました(笑)。
何の事かさっぱりだったのですが、ググりまくって日本語やら英語やら読み漁って、ようやく移行完了。
まず、さくらインターネットを使っていて、PerlのDigest::SHAが使えないのでCPANをユーザレベルでインストール。こちらを参考にしました。
CPANでDigest::SHAをインストールしたものの、どういじってもPerlスクリプトから見られないので、仕方なくスクリプト内に、
use lib qw(〜場所〜);
を書くことに。これにより、
use Digest::SHA qw(hmac_sha256_base64);
を書けます。
で、後は各パラメータをソートした後、「hmac_sha256_base64」を使用してSignatureパラメータを作ってやるわけですが、この辺を参考にすればOK。
ただし、日本語のキーワードで検索する場合は、
ecs.amazonaws.jp /onca/xml AWSAccessKeyIdやらのパラメータ
の方が良さそう。さらに、AssociateTagパラメータがあると必ずエラーが返ってくるようなので除外。エラーにはなりませんが、私はSubscriptionIdも除外しました。
なお、Perlでの変更の要点は、以下の通り。一部前述と重複します。なお、リクエストパラメータは、既にURIエスケープされているものとします。
Digest::SHAのhmac_sha256_base64を使う。
use Digest::SHA qw(hmac_sha256_base64);
タイムスタンプは「yyyy-mm-ddThh:mm:ssZ」形式。次のサブルーチンで生成できます。
sub gettimestamp { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); my $ts = sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",$year+1900,$mon+1,$mday,$hour,$min,$sec); $ts =~ s/:/%3A/g; return $ts; }
署名を作るサブルーチン。シークレットアクセスキーを「0123456789」と仮定。
sub getsignature { my($sortedparams) = @_; my $data = "GET\n"."ecs.amazonaws.jp\n"."/onca/xml\n".$sortedparams; my $key = '0123456789'; my $signature = hmac_sha256_base64($data, $key); $signature .= '=' while length($signature) % 4; return URI::Escape::uri_escape($signature); }
Webサービスへのリクエストパラメータは、アルファベット順にソートしておく。
my $timestamp = gettimestamp(); my $sortedparams = "AWSAccessKeyId=........&ItemPage=1&Keywords=.......&Operation=ItemSearch&ResponseGroup=Medium&SearchIndex=.......&Service=AWSECommerceService&Timestamp=$timestamp&Version=2009-01-06";
このサブルーチンを呼び出して、Signatureパラメータとしてリクエストに加えます。
my $signature = getsignature($sortedparams); my $requesturl = "http://ecs.amazonaws.jp/onca/xml?$sortedparams&Signature=".$signature;
これで、リクエストが可能になります。