こんにちは、IDプラットフォーム技術の近藤裕介です。
OAuthを使ったアプリを実装している方の多くは特にパラメータの署名まわりの部分で少し詰まることが多いように見受けられます。署名はOAuthのキモとなる仕組みなので今回はこれに関する記事を書いてみようと思います。
署名の仕組み
OAuth(以後OAuth Core)の仕様では、一般的な署名の仕組みを使ってリクエストの内容の改ざんや送信者のなりすましをされにくくしています。いまのところ以下の3つの署名方式に対応しています。
- HMAC-SHA1
Service Provider(以後SP)側でConsumerkeyとSecret(秘密鍵)のペアをConsumerに発行し、APIリクエストのパラメータなどから生成したBase Stringに対して秘密鍵とハッシュ関数を用いて生成した文字列を署名値としています。
Nonceと呼ばれる1回限り使い捨てのランダム値とtimestamp値もBase Stringに含めることでリプレイアタックへのセキュリティ対策を実現しています。 ヤフーではToken取得時、及びAPIアクセス時の署名方式にHMAC-SHA1をサポートしております。
- RSA-SHA1
Consumer側で公開鍵と秘密鍵を生成し、事前に公開鍵をSPに登録しておいて署名の検証を行えるようにした仕組みです。Consumer側はHMAC-SHA1と同様にAPIリクエストパラメータ及びNonceやTimestampを含めたBaseStringを生成し、秘密鍵とハッシュ関数を用いて生成した文字列を署名値としてリクエストに含ませています。ヤフーではこの署名方式をサポートしていません。
- plaintext
厳密には署名ではないのですが、単に秘密鍵を&でつなげた文字列を署名値として扱います。もっともシンプルな方法ですが秘密鍵が晒されている状態でパラメータの改ざん検知もできないため、通常はHTTPSで提供されているAPIのように通信内容が保護されている場合のみの利用に限定されます。ヤフーではToken取得時のみplaintextをサポートしており、APIアクセス時には使用できません。
署名方式の用途を拡張
OAuth Coreの署名の仕組みを一般化して、二者間の通信時にも適用させたものとして2-legged OAuthと呼ばれる仕様があります。
OAuth Coreはフロー上の登場人物がConsumerとSPとEnd Userの三者であることから3-legged OAuthと呼ばれているのに対し、ConsumerがEnd Userとは紐づかないSPのリソースにアクセスする2者間通信の仕組みを通称2-legged OAuthと呼んでいます。正式には OAuth Consumer Request という拡張仕様として定義されています。
2-legged OAuthは2者間の信頼があればどのサーバ間通信でも利用可能です。OpenSocialでは、単純に署名付きRequest(Signed Request)などとも呼ばれており、主にWebページ上で動作するMixiアプリやGoogle Gadgetなどガジェットから外部APIにアクセスする際に利用されています。SPが2-legged OAuthを利用することの利点は、ユーザ認証が不要なAPIにアクセス元を特定するACL機能を実装する際に、わざわざ独自の署名を実装せずにOAuth Coreの署名検証部分のロジックをそのまま利用できるということです。また、そのAPIを利用するConsumerの開発者にとっても既存のライブラリを使って署名を生成できるというメリットもあります。
OAuth Coreの仕組みではSP上のユーザのリソースにアクセスするためにAccess Tokenが必要ですが、2-legged OAuthではYDN記載のフロー図(提供終了)でいう1〜3のステップは不要でダイレクトにAPIアクセスを行います。
POSTリクエストでの署名方法
OAuth CoreではPOSTでリクエストする際の署名については、BODYの内容がKey=Value形式(Content-typeがapplication/x-www-form-urlencoded)のときのみに限定されています。そのため画像などのバイナリファイルやXMLやJSONなどをリクエストに含めて送信するタイプのAPIはOAuthの仕組みにのることができません。これらを解決するための拡張仕様として OAuth Request Body Hash が定義されています。
仕組みは単純で、BODYの内容のダイジェスト値を生成してBase64エンコードしたものをoauth_body_hashというパラメータに指定するのみで、あとはOAuth Coreと同様の手順で署名値を生成します。
OAuth Coreの署名方式の今後
OAuth Coreの次期バージョンを見据えた最近の流れとしては、リソースアクセス時の署名の仕組みをもっと簡素化して利用を促進しようと動きが高まってきています。正式な仕様ではありませんが OAuth WRAP という仕組みでは、OAuthの一連のフローにおいての署名に相当する部分を簡素化する代わりにHTTPS経由でSecretをそのまま付加するだけでよいという仕様が提案されています。これはOAuthの署名方式のうちPlaintextと似た考え方で、HTTPS自体が暗号化及び署名の仕組みを使用した通信であるため、あえて煩雑な手順で署名を生成せずとも十分セキュリティは担保できるのではないかと考えられているからだと思います。
ただ、SPの持つ全てのAPIをSSL化するのはパフォーマンス面においては現実的ではありませんし、WRAPの仕様ではtimestampやnonceといったパラメータも省かれており、APIを提供するSPにとって検討すべきセキュリティ対策の課題が多くなり、敷居が高くなるように感じています。
それでも、署名周りの仕様が簡単になればConsumerを実装する開発者側の負担はだいぶ軽減されるのでメリットは大きいと思います。これにより安全なリソースアクセスのプロトコルとしてのOAuthがどんどん広まってくれることを期待しています。
さいごに
OAuthのJSライブラリを使った署名生成サンプルがわかりやすかったので、これに2-legged OAuthとRequest Body Hashを加えた場合でも署名を確認できるようなツールを作成しました。
確認ツールはこちら
※上記、確認ツールを実際にお試しいただく方への注意事項署名の確認ツールは、
記事説明におけるサンプルとなります。
ご利用の際に生じた問題については一切責任を負いませんのでご注意ください。
参考URL
- Using OAuth for Consumer Requests (Draft 2) http://oauth.googlecode.com/svn/spec/ext/consumer_request/1.0/drafts/2/spec.html
- OAuth Request Body Hash http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
- OAuth Web Resource Authorization Profiles Version 0.9.7.2 http://oauth-wrap-wg.googlegroups.com/web/WRAP-v0.9.7.2.pdf
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました