タイトルに在るように、Amazonの新APIでのRequestへの電子署名時に使用するSHA-HM用のキー(極秘鍵)を安全に設定する方法を考えてみることに。
エンドユーザの環境で実行されるスクリプト言語の場合、安全に利用可能と思われる方法は無い。これは、「加工すると署名に利用できる値」「その値を署名として利用する為のロジックソース」が、見えてしまう為。
# Javaは、コンパイルしてバイナリでの配布となるものの、逆コンパイルも容易であることに注意。Flashや.NET上で動作するアプリケーションも同様の注意が必要な可能性あり。
エンドユーザの環境で実行されるバイナリアプリケーションである場合、解析をより複雑に(手間をかけさせる)ことは可能であるが、解析不可能にする方法はない。
・アプリケーションに埋め込む際に可逆な暗号化を施す。実行ファイルをdumpしただけで判る・・・というのは避ける。
・一般的な/標準的なSHA-HMライブラリを使用しない。ライブラリの呼び出しポイントをhookされるのを避ける(WindowsのDLLなど、動的リンクされるものは特に注意)
・sha-hmの演算の途中の値を保持し、鍵には戻さない(sha-hmの処理自体を、その途中の値から継続して処理可能なロジックに作り変える必要あり(※2))
どちらにしても、requestに署名を行う為には、もともとの鍵に戻す必要がある(※1)。そのため、「いかに、戻ったタイミングを知られないか」ということを注意するしかない。
※1 鍵が使用するsha-hmの1ブロックよりも長ければ、最初に1度、shaがかかるので不可逆になるが、今回は該当しない。
なお、鍵そのものが必要ない(たとえば、不可逆なハッシュ値が使えるとか)というように変更されたとしても、任意のrequestの文字列に正しく署名するための値を持つには変わりないので、なんらかの、「盗用すると、勝手に署名できる値」を含む必要があり、結果として、(鍵の値はばれてないけど偽装はされるという)あまり、鍵の秘密性を上げた意味がない結果になるような気がする。
# 鍵の値が他のことにも使えれば、値そのものがばれないことに意味があるんですが、署名で使う以外になにもないような?
上記2つについて、(1)APIへのリクエストそのもの、もしくは、(2)リクエストに署名をする部分のみについて、サーバサイドで実行するという手も考えられる。(2)の欠点は余分なサーバへの通信が発生すること。(1)と(2)の共通の欠点として、このサーバでの署名処理がネックになる可能性があることと、この処理とこれに依頼してくる処理の間の認証をしっかりしないと、このサーバでの処理自体が悪用される可能性があるということ(だれからの要求でも、自身の署名をつけてしまったら、大問題。が、署名サービス(requestの文字列を送ると、署名したrequestの文字列が得られる)とか善意で作っちゃう人が出てくる可能性も0ではないかも。)
※2 以下のタイミングの値を利用できるかも(名称は、shaおよびhmacの仕様を参照)
1.key0
(この値は鍵を逆算可能)
2.以下の2つ(可逆なのでkey0^ipdaの値から、key0^idap^ipad^opadとしてもう一方を求めることも可能。)
key0^ipad
key0^opad
(この値は(どちらの値からでも)鍵を逆算可能)
3.以下の2つ
key0^ipadをsha256で処理した1ブロック目としてのa~h相当
key0^opadをsha256で処理した1ブロック目としてのa~h相当
(実質、keyを1ブロックとしてshaしたのと大差ない。不可逆)
4.「3.」の値+α
続くブロックについて、可能な限り予め演算してその途中となる値を持つころで、そこまでの文字列を改変不能とすることが可能。ただし、常に先頭からしか適用できない。
「3.」もしくは「4.」の値を、他の2案(可逆に暗号化する、ライブラリなど区切りの判る呼び出しをしない)を混ぜることで、かなり解読は困難となりそう。おそらく、ここが限界・・・・か?
この方法であれば、JavaScriptに埋め込んでも、鍵の値そのものは求めることが出来ないようにすることは可能。ただし、「requestを発行できるソース」という点には変わりないので、鍵の値そのものがばれていないだけで、署名自体は盗用される状態になってしまうため、意味は薄い(利用規約への言い訳以外の目的は思いつかない)。なにか、もうひとひねりしてJavaScriptから安全に利用可能だったりすると良いんですが・・・いまのところ思いつきません。
余談。
2009/05/21現在では、Request中のTimestampのパラメータについて、未来側での上限制限がかかっていないっぽい。そのため、呼び出すサービスの内容(requestの文字列)が完全に固定でよいのであれば、未来のTimestampにてrequestを生成し予め署名をしておくことで、固定リンクからawsを利用することは可能。このこの場合、リンクに含まれる値(署名対照の文字列と生成されたSignature)から鍵を求めることはできず、また書き換えたrequestに用いられてしまうことも無い為、安全ではある。
最近のコメント