Bug(バグ) #3232
Yuya Watanabe さんが約12年前に更新
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 クライアントに影響が出るため,シークレットがある場合とない場合での署名の検証を行い,メジャーバージョンアップ時にシークレットがない場合の検証を取り除くという対応が考えられる. この対応を行う場合にはメジャーバージョンアップ時に確認できるチケットを作成しておく必要が有る.