SYNCER

SYNCER

OAuth1.0の署名(Signature)を作成する方法

公開日: 2014/08/09 / 更新日:

OAuth2.0が登場してからも、1.0を採用し続けるwebサービスはTwitter、Tumblr、500pxなど、まだまだ数多く残っています。今回はOAuth 1.0認証における署名(Signature)の作成方法を紹介します。なお、この記事で説明する署名の作成方式は「HMAC-SHA1」です。

OAuth1.0の署名とは?

署名って何?

署名とは、簡単に言うと、URLアドレスとパラメータ+αを暗号化したものです。「OAuth1.0」という認証方式を採用したAPIを利用する場合、リクエストするパラメータに応じて、署名(Signature)となるキー(暗号)を作成し、一緒に送信しなければいけません。APIを提供するサービス側は、アプリケーション側が送ってきたパラメータと、この署名を照合し、署名が正しくない場合、エラーを返します。これにより不正な第三者のリクエストを防ぎます。

OAuthの仕組みを深く理解したい場合、下記文献が参考になります。内容は公式ドキュメント(英語)の方が充実していますが、分かりやすさを求めるのなら、まずWikipediaをご覧下さい。とはいえ、一番理解を助けるのは、実際にプログラミングをすることです。私は下記の文献をほとんど読んでいません。

HMAC-SHA1とは?

「HMAC-SHA1」とは、データの変換方式の1つです。OAuth1.0における署名を作成するには、このHMAC-SHA1という製法が多く用いられているというわけです。HMAC-SHA1製法を覚えておけば、世の中のOAuth1.0を採用したAPIのほとんどに対応できるはずです。例により、下記に参考文献を紹介しますが、読む前にプログラミングをした方が、理解は速いはずです。

署名作成に必要な要素

OAuth1.0認証における署名を作成するには通常、下記4つの値が必要です。その内、純粋に署名を作成する部分だけを見ればoauth_consumer_secretとoauth_token_secretが必要となります。oauth_token_secretに関しては、存在しない場合はなし(空の文字列)が値となります。

oauth_consumer_key
アプリケーションごとに割り当てられたID。webサービスによって「API Key」「Consumer Key」など呼称が違う。
oauth_consumer_secret
oauth_consumer_keyの対となるキー。webサービスによって「API Secret」「Consumer Secret」など呼称が違う。
oauth_token
アプリケーションを利用するアクセス、ユーザーごとに割り当てられたID。「リクエストトークン」「アクセストークン」など。
oauth_token_secret
oauth_tokenの対となるキー。「リクエストトークンシークレット」「アクセストークンシークレット」など。

署名作成の流れ

大仰な説明をしてきたものの、その実は、署名の作成は下記の3ステップで構成される「単純な作業」です。「キー」と「データ」の作り方、そして「変換方法」を次の章で覚えてしまいましょう。

  1. 「キー」を作成する。
  2. 「データ」を作成する。
  3. 「キー」と「データ」を、HMAC-SHA1を用いて署名に変換する。

プログラミング

リクエスト内容

ここからは、サンプルを用いて実際にOAuth1.0における署名(HMAC-SHA1方式)を作成していきます。下記が今回、想定するサンプルのリクエスト内容です。

リクエストURL
http://example.com/sample.php
メソッド
POST
パラメータ
title=AAA&name=BBB&text=CCC

また、次の値のoauth_consumer_secret、oauth_token_secretを所有していると仮定します。

oauth_consumer_secret
bbbbbb
oauth_token_secret
dddddd

手順1: キーの作成

MAC-SHA1の変換方式を用いるためには、「データ」と「キー」が必要です。まずは「キー」を作成してみましょう。その作り方は簡単で、oauth_consumer_secretとoauth_token_secretをURLエンコードして、&で繋げるだけです。

ほとんどの場合、oauth_consumer_secretとoauth_token_secretの値は半角英数字なのでURLエンコードをしても意味がありません。が、定義上そうなっていることを覚えておきましょう。

bbbbbb&dddddd

oauth_token_secretが存在しない場合

OAuth1.0認証をしている上でoauth_token_secretの値がまだ存在しないケースがあります。その場合は次のようにoauth_token_secretをなし(空の文字列)にしてキーを作成して下さい。

bbbbbb&

サンプルコード

キーを作成するサンプルコードです。

PHP (oauth1.php)

<?php
	// oauth_consumer_secret
	$oauth_consumer_secret = 'bbbbbb' ;

	// [oauth_consumer_secret]をURLエンコード
	$encode_a = rawurlencode( $oauth_consumer_secret ) ;

	// oauth_token_secret
	$oauth_token_secret = 'dddddd' ;

	// [oauth_token_secret]をURLエンコード
	$encode_b = rawurlencode( $oauth_token_secret ) ;

	// 2つの値を[&]で繋いで署名キー[$signature_key]が完成する
	$signature_key = $encode_a . '&' . $encode_b ;

	// 確認用 (本番では消して下さい)
	var_dump( $signature_key ) ;

デモを開く

手順2: データの作成

続いて「データ」を作成していきましょう。作成方法は次の通り、5ステップの構成です。

  1. パラメータをアルファベット順にキー=値&キー=値&...と繋ぐ。
  2. 組み立てたパラメータを、URLエンコードする。
  3. リクエストメソッドを、URLエンコードする。
  4. リクエストURLを、URLエンコードする。
  5. リクエストメソッド、リクエストURL、パラメータの順番に&で繋げる。

パラメータの組み立て

まずは1番です。パラメータをアルファベット順に、キー=値&キー=値&...という形式に組み立てます。サンプルのパラメータを用いると、nametexttitleをアルファベット順に並び替えて次のようになりますね。

name=BBB&text=CCC&title=AAA

パラメータをエンコード

続いて、組み立てたパラメータをURLエンコードします。すると次のようになります。

name%3DBBB%26text%3DCCC%26title%3DAAA

リクエストメソッドをエンコード

リクエストメソッドを、URLエンコードします。元々、英字なので、実質的に意味はありませんが、形式的に行なっておきましょう。サンプルを元にすると次の通りです。

POST

リクエストURLをエンコード

続いて、リクエストURLを、URLエンコードします。サンプルを元にすると次の通りです。

http%3A%2F%2Fexample.com%2Fsample.php

3つの要素を&で繋ぐ

最後に、「リクエストメソッド」「リクエストURL」「パラメータ」の順番に&で繋げます。サンプルでは次の通りになります。分かりやすいように色分けをしてあります。

POST&http%3A%2F%2Fexample.com%2Fsample.php&name%3DBBB%26text%3DCCC%26title%3DAAA

サンプルコード

データを作成するサンプルコードです。

PHP (oauth1.php)

<?php
	// リクエストメソッド(URLエンコード)
	$request_method = rawurlencode( 'POST' ) ;

	// リクエストURL(URLエンコード)
	$request_url = rawurlencode( 'http://example.com/sample.php' ) ;

	// パラメータ(連想配列形式)
	$params = array(
		'title' => 'AAA' ,
		'name' => 'BBB' ,
		'text' => 'CCC' ,
	) ;

	// 連想配列のキーをアルファベット順に並び替える
	ksort( $params ) ;

	// 配列の各パラメータの値をURLエンコード
	foreach( $params as $key => $value ) {
		$params[ $key ] = rawurlencode( $value ) ;
	}

	// 連想配列[$params]を[キー=値&キー=値]の形式に組み立てる
	$request_params = http_build_query( $params , '' , '&' ) ;

	// 組み立てたパラメータをURLエンコードする
	$request_params = rawurlencode( $request_params ) ;

	// メソッド[$request_method]、URL[$request_url]、パラメータ[$request_params]の順に[&]で繋げる
	$signature_data = $request_method . '&' . $request_url . '&' . $request_params ;

	// 確認用 (本番では消して下さい)
	var_dump( $signature_data ) ;

デモを開く

手順3: キーとデータを署名に変換

仕上げに作成した「データ」と「キー」を使って署名を作成します。次の手順になります。

  1. 「データ」「キー」を用いて、HMAC-SHA1方式のハッシュ値を生成する。
  2. ハッシュ値をbase64エンコードする。

HMAC-SHA1方式のハッシュ値に変換

まず、データ()とキー()を使って、HMAC-SHA1方式のハッシュ値を生成します。PHPでは次の通りです。

PHP

// HMAC-SHA1方式のハッシュ値に変換
$hash = hash_hmac( "sha1", $signature_data, $signature_key, TRUE ) ;

ハッシュ値をbase64エンコード

最後に出来上がったハッシュ値()をbase64エンコードして署名の完成となります。

PHP

// ハッシュ値をbase64エンコード
$signature = base64_encode( $hash ) ;

完成した署名

サンプルを元にした署名()は次の通りとなります。自分がやったものと照らし合わせてみて下さいね!

mu4s4b2t4T0HsjD0z0J749fMGPA=

サンプルコード

署名を作成する一連の流れを1つのプログラムにまとめてみました。パラメータを色々と変更して、署名がどのように作成されるのか、確認してみて下さい。

PHP (oauth1.php)

<?php
	// oauth_consumer_secret
	$oauth_consumer_secret = 'bbbbbb' ;

	// [oauth_consumer_secret]をURLエンコード
	$encode_a = rawurlencode( $oauth_consumer_secret ) ;

	// oauth_token_secret
	$oauth_token_secret = 'dddddd' ;

	// [oauth_token_secret]をURLエンコード
	$encode_b = rawurlencode( $oauth_token_secret ) ;

	// 2つの値を[&]で繋いで署名キー[$signature_key]が完成する
	$signature_key = $encode_a . '&' . $encode_b ;

	// リクエストメソッド
	$request_method = 'POST' ;

	// リクエストURL
	$request_url = 'http://example.com/sample.php' ;

	// リクエストメソッドをURLエンコード
	$request_method = rawurlencode( $request_method ) ;

	// リクエストURLをエンコード
	$request_url = rawurlencode( $request_url ) ;

	// パラメータ(連想配列形式)
	$params = array(
		'title' => 'AAA' ,
		'name' => 'BBB' ,
		'text' => 'CCC' ,
	) ;

	// 連想配列のキーをアルファベット順に並び替える
	ksort( $params ) ;

	// 配列の各パラメータの値をURLエンコード
	foreach( $params as $key => $value ) {
		$params[ $key ] = rawurlencode( $value ) ;
	}

	// 連想配列[$params]を[キー=値&キー=値]の形式に組み立てる
	$request_params = http_build_query( $params , '' , '&' ) ;

	// 組み立てたパラメータをURLエンコードする
	$request_params = rawurlencode( $request_params ) ;

	// メソッド[$request_method]、URL[$request_url]、パラメータ[$request_params]の順に[&]で繋げる
	$signature_data = $request_method . '&' . $request_url . '&' . $request_params ;

	// HMAC-SHA1方式のハッシュ値に変換
	$hash = hash_hmac( 'sha1' , $signature_data , $signature_key , TRUE ) ;

	// ハッシュ値をbase64エンコードして署名の完成
	$signature = base64_encode( $hash ) ;

	// HTML用
	$html = '' ;

	// 実行結果
	$html .= '<h2>実行結果</h2>' ;
	$html .= '<dl>' ;
	$html .= 	'<dt>URL</dt>' ;
	$html .= 		'<dd>' . $request_url . '</dt>' ;
	$html .= 	'<dt>メソッド</dt>' ;
	$html .= 		'<dd>' . $request_method . '</dt>' ;
	$html .= 	'<dt>パラメータ</dt>' ;
	$html .= 		'<dd>' . $request_params . '</dt>' ;
	$html .= 	'<dt>完成した署名</dt>' ;
	$html .= 		'<dd>' . $signature . '</dt>' ;
	$html .= '</dl>' ;

	// ブラウザに[$html]の内容を出力
	echo $html ;

デモを開く