プロジェクト

全般

プロフィール

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

戻る