Twitterで @angel_p_57 さんからご指摘頂いて実装を追加した。
もともとパスワードより危ういというツイートを見て、色々聞いていると、おっしゃっている内容としては署名が流出した場合に、それを悪意を持って利用すると認証が突破できてしまうという問題提起を頂いているようだった。
一方で、僕自身は今回実装した認証はパスワード認証と比較すると危ういかというとそうとは思わない。理由としては下記がある。
- STNSを利用するインフラはHTTPSを前提としており、署名の盗聴や、クライアントプログラムに任意の署名を行わせることがそもそも困難である
- 署名が流出したとして、その署名がそのまま利用できるかどうかはサーバサイドで同じパラメーターの受け取り方や、同じ署名対象データを利用していないと認証は通らないので、必ずしも署名が使い回せるわけではない。要するにSSHなどと異なり、パラメーターの受け渡し方法にはグラデーションがある。
- セキュリティ的には無意味な要件ではあるが、署名検証に利用する公開鍵はSTNSで管理されているので、そもそも消してしまえばその流出した署名の検証が通らなくなる。セキュリティ的に無意味なのは流出すると単位時間あたりに処理できる内容は昨今膨大なので、すぐ消せばいいとかそういう話ではないから。
加えて僕自信のユースケースとしては多要素認証の一要素としてこの認証を用いていたたため、署名の流出というかなり高い攻撃難易度を考えると妥当な実装であると考えている。
しかし、セキュリティ上安全であるに越したことはないので、利用者の意図を持って署名の再利用が困難になるようなチャレンジコードによる認証を追加した。実装としては認証前にクライアントからサーバにチャレンジコードを要求し、それに対する署名を作成して、サーバサイドでチャレンジコードと署名の検証を行うようにした。なおこのチャレンジコードは一回しか利用できない。これによって署名そのものが流出したとしても、その署名を利用したなりすましは原理的に困難になる。
考えられる攻撃ケースとしては悪意を持ったサーバが正規サーバにチャレンジコード要求を行い、払い出された値を、たまたま悪意を持ったサーバにチャレンジ要求を投げてきたクライアントに、正規サーバから払い出されたチャレンジコードを払って署名させるみたいなケースだが、これを防ぐならば何かしらのサーバ、クライアントを認証する仕組みのTLSクライアント認証なり、何かしらのシークレットキーを互いに持ち合うなどを追加すると良さそう。
最後に、今回Twitterでお話させてもらって思ったのだが、セキュリティの評価をするときにユースケースや背景にある技術をすり合わせずに話すと、原理的な話だけしかできなくて、攻撃容易性や危険度について正しい評価がされないなぁと感じたので、議論のベースをすり合わせてから話すのちゃんとやらないとなぁと思った。