プロジェクト

全般

プロフィール

Bug(バグ) #3232

Yuya Watanabe11年以上前に更新

h3. 概要

OAuth のアクセストークンを取得していくる際にシークレットキーを用いた署名を検証できない.
クライアントは通常アクセストークンを取得してくる際に,事前に生成されているリクエストトークンとリクエストトークンのシークレットを用いて署名を行なう.しかし,クライアント側で正しいシークレットを用いた署名の実装を行なっていても,署名の検証に失敗してアクセストークンが取得できない. クライアントがアクセストークンを取得してくる際に,事前に生成されているリクエストトークンとリクエストトークンのシークレットを用いて署名を行なっている.しかし,クライアント側で正しいシークレットを用いた署名の実装を行なっていても,署名の検証に失敗してアクセストークンが取得できない.

h3. 原因

サーバ側では下記コード部のように,リクエストトークンを取得してくる際にシークレット部分を空文字列としており,このトークンオブジェクトを用いて署名を検証してしまう.
そのため,おそらくシークレットが空文字列であるトークンオブジェクトとして署名の検証を行なってしまうとおもわれるため,クライアントの実装がシークレットを空にするようになっている場合には成功するものと思われる.
(コードは 3.6.6 のもの)

lib/action/opOAuthTokenAction.class.php 86 行目
<pre>
75 public function executeAccessToken(sfWebRequest $request)
76 {
77 require_once 'OAuth.php';
78
79 $authRequest = OAuthRequest::from_request();
80 $requestToken = $authRequest->get_parameter('oauth_token');
81 $this->information = $this->getTokenTable()->findByKeyString($requestToken);
82 $this->forward404Unless($this->information);
83 $this->forward404Unless($this->information->getIsActive());
84 $this->forward404Unless($this->information->getVerifier() === $authRequest->get_parameter('oauth_verifier'));
85
86 $token = $this->getServer()->fetch_access_token($authRequest);
87
88 $this->information->delete();
89
90 $this->getResponse()->setContent((string)$token);
91
92 return sfView::NONE;
93 }
</pre>

lib/vendor/OAuth/OAuth.php 470 行目
<pre>
460 /**
461 * process an access_token request
462 * returns the access token on success
463 */
464 public function fetch_access_token(&$request) {
465 $this->get_version($request);
466
467 $consumer = $this->get_consumer($request);
468
469 // requires authorized request token
470 $token = $this->get_token($request, $consumer, "request");
471
472
473 $this->check_signature($request, $consumer, $token);
474
475 $new_token = $this->data_store->new_access_token($token, $consumer);
476
477 return $new_token;
478 }
</pre>

lib/vendor/OAuth/OAuth.php 548 行目
<pre>
543 /**
544 * try to find the token for the provided request's token key
545 */
546 private function get_token(&$request, $consumer, $token_type="access") {
547 $token_field = @$request->get_parameter('oauth_token');
548 $token = $this->data_store->lookup_token(
549 $consumer, $token_type, $token_field
550 );
551 if (!$token) {
552 throw new OAuthException("Invalid $token_type token: $token_field");
553 }
554 return $token;
555 }
</pre>

lib/util/opOAuthDataStore.class.php 110 行目
<pre>
105 public function lookup_token($consumer, $token_type, $token)
106 {
107 $tokenRecord = $this->getTokenTable()->findByKeyString($token, $token_type, $this->queryTemplate);
108 if ($tokenRecord)
109 {
110 $token = new OAuthToken($tokenRecord->getKeyString(), '');
111 if ('request' !== $token_type)
112 {
113 $token->secret = $tokenRecord->getSecret();
114 }
115 return $token;
116 }
117
118 return null;
119 }
</pre>

h3. 修正案

lib/util/opOAuthDataStore.class.php 110 行目の空文字列のシークレットではないものを返す.
ただし,そのまま修正してしまうと既存の OpenPNE OAuth クライアントに影響が出るため,シークレットがある場合とない場合での署名の検証を行い,メジャーバージョンアップ時にシークレットがない場合の検証を取り除くという対応が考えられる.
この対応を行う場合にはメジャーバージョンアップ時に確認できるチケットを作成しておく必要が有る.

戻る