できるTypeKey

Typekey認証(Ver.1.1)の基本的な仕組み。日本語の資料があんまり無い感じだったのでまとめてみました。 暗号とかセキュリティとかそーゆーの余り詳しくないので間違ってるかもしれませんすいませんごめんなさい。

MovableTypeに特化した話ではなく、Typekeyの認証の仕組み自体の説明。同様の仕組みを利用すれば MovableType、typekey.com以外でも再現可能。

概要

認証を行わない更新可能なページの場合、

該当ページ --> 書込CGI --> 書込処理 --> 書込結果ページ

となりますが、TypeKey認証を行う場合、

該当ページ --> 書込CGI --> TypeKeyログインページ(typekey.com) -->
書込CGI --> 書込処理 --> 書込結果ページ

となります。要するに、一度、外部にあるTypeKey用のログインページに飛ばされて、認証に成功したら、元のCGIに戻ってきて 処理が続行される、と言う具合です。

TypeKey認証は認証が必要なサイト(クライアント)と実際に認証を行い、認証結果を返すサイト(サーバー)から構成されます。

クライアント - サーバー間の情報のやり取りは全てGET引数を用いて行います。

GET引数仕様

クライアントからサーバーに遷移する状態を「リクエスト時」、 認証後、サーバーからクライアントに遷移する状態を「レスポンス時」と表記します。

  • リクエスト時
    パラメータ名説明
    vTypeKey認証のバージョン(1.1を設定)
    need_emailレスポンスにユーザーのメールアドレス情報を付加するか(1=付加する)
    t自サイトのトークン(TypeKey登録時に設定したもの)
    _return認証後に遷移するURL(基本的には現在のURL)
  • レスポンス時
    パラメータ名説明
    emailユーザーのメールアドレス、又はメールアドレスのハッシュ値(need_emailの場合のみ)
    nameユーザー名
    nickユーザーのニックネーム(2バイト文字可能。UTF-8でURLEncodeされている)
    ts認証された日時
    sigGET引数の各値が改竄されていない事を保障するための文字列

クライアント側

事前準備として自サイト用のトークンを作成しておく。

トークン(token)
暗号化、復号化の為にしようされる自分のサイトを特定する文字列。TypeKey登録時に自サイトのURLを指定するとTokenが発行される。*1

つまり、自サイトのURLをサーバー側に事前に登録しておく必要があります。 トークンは本来はサイト情報と結びつくものであり、ユーザーとは直接的に関係ありませんが、 typekey.com では、サイト、トークンをユーザーとも結び付けている(ユーザー情報の1つとして捉えている)為、 トークンを取得するためには、まず自分自身がTypeKeyユーザーになる必要があります。

リクエスト時のGET引数、レスポンス時のGET引数は「GET引数仕様」を参照。

コメント等の何らかページの更新が起こるような仕組みがある場合、そのPOST先のscript内で、以下のような処理を行う。

  1. TypeKey用のセッション情報が存在するかを確認
    • 自分で適当にセッション名は考える
    1. 存在しない場合、TypeKeyサーバーのログイン用URLにリダイレクト
      • この際、GET引数を仕様に従って付加
    2. 存在する場合は既に認証済みとみなし、更新処理等を行う(Typekey認証は行われない)
  2. サーバー側のログインページにて認証が行われ、認証成功の場合は、_returnのURLにリダイレクトされて戻ってくる
    • この際、GET引数が仕様に従って付加されている
  3. 戻り値のGET引数が改竄されていないかの検証を行う(DSA暗号方式)
    1. サーバー側の公開キーを取得*2
    2. DSA暗号のロジックに従い、email,name,nick,ts,token を :: で連結した文字列を公開キーで変換
      • email,name,nick,tsは戻り値のGET引数から取得
      • tokenは自サイトのトークン
    3. 変換後の文字列が sig と同一かどうかを確認
      • 同一の場合値は改竄されていない事が保障される
  4. サーバー側で認証された時刻と現在時刻の比較を行う
    • ts と現在時刻を比較する
    • 時間が基準より経過している場合は認証自体が古すぎるとして却下
      • リダイレクトURL自体はinternet上に晒されているので、同じURLを再利用すれば詐称されてしまう可能性がある
      • サーバー側での認証後数十秒〜数分以内のみ許可するのが通常(基本的には一瞬で戻ってくるはず)
  5. 認証時刻も問題ない場合は、認証成功とみなし、ユーザー情報をTypeKey用のセッションに格納
    • このセッション情報利用して次回以降の認証をクライアント側のみで完結させる
  6. 実際の更新処理を実行
    • 認証失敗、却下の場合はエラーページ等へ遷移

サーバー側

事前準備として、

  • DSA暗号方式に基づいた秘密鍵、公開鍵を生成
  • 公開鍵をinternet上に公開

が必要。又、当然、ログインするユーザーがユーザーDBに登録されている必要がある。

リクエスト時のGET引数、レスポンス時のGET引数は「GET引数仕様」を参照。

  1. 共通ログインページにユーザーがアクセスしてくる(各種GET引数付きで)
  2. ユーザーがIDとパスワードを入力してログイン
    • 非会員の場合は新規登録処理へ誘導
  3. ユーザーDBにてIDとパスワードを検証、ユーザー情報取得
  4. 検証成功後、DSA暗号のロジックに従い、email,name,nick,ts,token を :: で連結した文字列を秘密鍵で変換
    • email,name,nickはユーザー情報から
    • tsは現在日時
    • tokenはリクエスト時のGET引数から
  5. リクエスト時に指定された _return 文字列にユーザー情報とDSA変換後の文字列を sig として追加したURLにリダイレクト

特徴

  • ログイン処理自体は全てサーバー側で完結しているのでクライアント - サーバー間でパスワード情報をやりとりすることがない
    • クライアント側はパスワード管理を全くする必要がない
    • クライアント側は「認証」自体に関する処理を一切する必要がない
  • クライアントはサーバーから戻ってきた情報を信用して承認されたとみなすだけ
    • サーバーからリダイレクトされてきた、イコール ログイン完了した、とみなす
    • 本当にデータが信頼できるものかはDSA暗号を用いることによりクライアント側でチェック可能
  • クライアントは認証情報をSession等でキャッシュすることにより、サーバーへの通信(ログイン処理)を一度だけにすることが可能
  • サーバー側は基本的に必要な引数さえ揃っていれば、どこからのリクエストでも受け付ける
    • 認証処理を行って指定のURLにリダイレクトするだけ
  • 仕様、ロジックが明確なので、同様のサーバーを自前で組む事も比較的簡単(多分)

こんなんで平気なの?

認証サーバーとクライアントが全く別ドメインで独立して存在している為、 サーバー - クライアント間でのセッション情報共有みたいな事は 一切行っていません。

しかも、サーバーへのリクエスト情報、サーバーからのレスポンス情報も全てURLのGET引数として普通にアドレス欄に 表示された情報でやり取りされます。基本的にCookieも使用しません。(認証キャッシュの為にのみ使用)

一見すると「こんなんで平気なんかい」っつー感じですが、リクエスト時には基本的に戻ってくるURLを指定するだけですので、 見られちゃっても全然問題なし。 レスポンス時の情報も sniff された場合、ユーザー名とニックネームはバレちゃいますが、 メールアドレスはSHAでハッシュされているので、特定不可能。 又、パスワード情報は一切やり取りしないので、やはり解析不可能。 レスポンス時にクライアント側ではHTTP_REFERER等でサーバーからのアクセスかどうかみたいな事は一切見ていないので、クライアントのURLにそれっぽい引数付けてアクセスしたら行けちゃいそうですが、そこは sig をチェックすることによって、 本当にサーバー側で認証されたURL引数なのかを検証出来る為、不正なアクセスは排除可能。 レスポンスURL自体を sig も含め引数ごと sniff してそのURLを別のユーザーが使用したら認証を不正に突破されちゃうのでは? と言う感じですが、これも、URL引数にサーバー側のタイムスタンプを含める事でURL自体の有効期間をクライアント側で判断可能。 つまり、再利用しようとしても「有効期限切れ」と言うことで却下できる。 タイムスタンプ自体もURL引数の一部として sig 生成用データに利用されているのでタイムスタンプ自体を詐称することも不可能。

と、言うことで考えられる脆弱性としては、

認証の通信自体をリアルタイムで監視、sniff し、レスポンスのURLを確認後、即効でそのURLにアクセスされた場合

位です。 この場合も、CookieやIPアドレス情報等を利用して、 既にログインしているユーザーと同一ユーザー名(name)のアクセスが他のロケーションからあった場合は 拒否する、と言うようなロジックをクライアント側に入れれば解決できると思います。 もしくは、信用して認証キャッシュしたURLリストを有効期限ぎれまで保持しておいて、 1回しか同一URLでは信用しないっつーのでもいいかもしれないです。

と言う事で、こんなんで平気なんです。素晴らしい。

参考

このメソ知恵は訳に立ちましたか?

選択肢 投票
はい 31  
いいえ 24  

  • でも何かこの仕組みだと、コメントとかをPOSTで送った時に、サーバーにリダイレクトされて戻ってきたらPOSTの値が無くなっちゃうのでは・・・?もうちょい調査が必要っすな。 -- メソ 2005-06-10 (金) 21:23:00
  • 結構理解出来てきました。まとまったら更新します。 -- メソ 2005-06-14 (火) 22:29:32

URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White

*1 1つのtokenに対して複数のサイトを関連付けることも可能
*2 typekey.comの場合、http://www.typekey.com/extras/regkeys.txt