プロジェクト

全般

プロフィール

Bug(バグ) #3232

完了

OAuth のアクセストークンを取得していくる際にシークレットキーを用いた署名を検証できない

Yuya Watanabe さんが約12年前に追加. 7年以上前に更新.

ステータス:
Won't fix(対応せず)
優先度:
Normal(通常)
担当者:
対象バージョン:
開始日:
2012-10-16
期日:
進捗率:

0%

予定工数:
3.6 で発生するか:
Yes (はい)
3.8 で発生するか:
Yes (はい)

説明

概要

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

原因

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

lib/action/opOAuthTokenAction.class.php 86 行目

 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   }

lib/vendor/OAuth/OAuth.php 470 行目

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   }

lib/vendor/OAuth/OAuth.php 548 行目

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   }

lib/util/opOAuthDataStore.class.php 110 行目

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   }

修正案

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


関連するチケット 2 (0件未完了2件完了)

コピー先 OpenPNE 3 - Backport(バックポート) #3705: OAuth のアクセストークンを取得していくる際にシークレットキーを用いた署名を検証できないFixed(完了)isao sano2012-10-16

操作
コピー先 OpenPNE 3 - Backport(バックポート) #3706: OAuth のアクセストークンを取得していくる際にシークレットキーを用いた署名を検証できないFixed(完了)isao sano2012-10-16

操作

Yuya Watanabe さんが約12年前に更新

Yuya Watanabe さんが約12年前に更新

Yuya Watanabe さんが約12年前に更新

  • ステータスNew(新規) から Accepted(着手) に変更
  • 担当者Yuya Watanabe にセット

Yuya Watanabe さんが約12年前に更新

  • ステータスAccepted(着手) から Pending Review(レビュー待ち) に変更
  • 進捗率0 から 50 に変更

更新履歴 978cb7c92e9d4f10b0b7a8d3d469a63af980c0fa で適用されました。

Yuya Watanabe さんが11年以上前に更新

https://tools.ietf.org/html/rfc5849#section-2.1

When making the request, the client authenticates using only the
client credentials. The client MAY omit the empty "oauth_token"
protocol parameter from the request and MUST use the empty string as
the token secret value.

isao sano さんが約10年前に更新

  • コピー先 Backport(バックポート) #3705: OAuth のアクセストークンを取得していくる際にシークレットキーを用いた署名を検証できない を追加

isao sano さんが約10年前に更新

  • コピー先 Backport(バックポート) #3706: OAuth のアクセストークンを取得していくる際にシークレットキーを用いた署名を検証できない を追加

kaoru n さんが9年以上前に更新

  • 担当者 を削除 (Yuya Watanabe)

Youichi Kimura さんが約8年前に更新

  • ステータスPending Review(レビュー待ち) から Pending Testing(テスト待ち) に変更
  • 担当者Youichi Kimura にセット
  • 進捗率50 から 70 に変更
  • 3.6 で発生するかUnknown (未調査) から Yes (はい) に変更
  • 3.8 で発生するかUnknown (未調査) から Yes (はい) に変更

元のコードで opOAuthDataStore::lookup_token()$token_type'request' の場合のみ token_secret を空文字列にする実装となっているのは、OAuth 1.0a でのリクエストトークン取得時には署名に空の token_secret が使われることを意識したものではないかと思います。
しかし実際には、リクエストトークン取得時は常に新規のトークンを発行するため OAuthDataStore::lookup_token() が呼ばれることはありません。
一方で OAuthDataStore::lookup_token() でリクエストトークンを要求される場面はさらに後のアクセストークン取得時であり、この時点では request_secret を使用した署名が行われています。ここで token_secret を空文字列に書き換えてしまうと、クライアントが生成した署名と検証のために生成した署名が一致しないことになってしまいます。
よって、そもそも OAuthDataStore::lookup_token() を実装する上で token_secret を空にする処理は不要であり、DB から取得したトークンの組をそのまま返せばよいことになります。

以上のことから今回の不具合は 978cb7c9 の修正で問題ないと判断しました。

Youichi Kimura さんが約8年前に更新

下記の手順で動作確認できます (https://gist.github.com/upsilon/9a3ad8fb319276519ef90abe5f472235 を使用する):

$ wget https://github.com/openpne/OpenPNE3/raw/OpenPNE-3.8.20/lib/vendor/OAuth/OAuth.php
$ wget https://gist.github.com/upsilon/9a3ad8fb319276519ef90abe5f472235/raw/25ad4b89a529e0235436cbcbdad557645eb7215f/apitest.php

$ vim apitest.php # BASE_URL, CONSUMER_KEY, CONSUMER_SECRET を書き換え
$ php apitest.php
Authorize URL: http://sns.example.com/pc_backend.php/oauth/authorize?oauth_token=***
PIN Code > (Authorize URLにアクセスして表示されるPINコードを入力)

isao sano さんが7年以上前に更新

  • ステータスPending Testing(テスト待ち) から Won't fix(対応せず) に変更
  • 進捗率70 から 0 に変更

OpenPNE 3.8.23 にて対応済みであったため、対応せずとします。

他の形式にエクスポート: Atom PDF