web-dev-qa-db-ja.com

パスワードではなく署名によるクライアント側の認証

ユーザーが生成したデータを、それを生成したユーザーの署名を付けて保存したい(ユーザーがフォームにデータを入力する必要があり、書き込んだデータに署名してもらいたいとしましょう)。

サーバー側は、ランダムなサーバー言語(必要なすべてをカバーするのに十分な大きさのライブラリーを備えています)、クライアント側はJavascript(WebアプリケーションはSPA、単一ページアプリケーション)です。クライアントマシンはセルラーにすることができます(かなり新しいスマートフォンですが、それでも標準のデスクトップ/ラップトップと比較して遅いCPU)

DBバックエンドは「安全ではありません」。データを改ざんすることは可能ですが(多くの人がマシンにアクセスでき、おそらく「クラウド」にあります)、すでに書き込まれたデータ(と同様のもの)を改ざんすることが非常に困難な強力な連続した連続バックアップがあります。安全なシーケンシャルログ)(おそらく、ログのダイジェストが安全なサーバーに継続的に送信されるか、シーケンシャルログが最初のクラウドとは完全に別のクラウドに保持されるか、ランダムなマシンでさえ、ハッシュを保存するだけでよい場合出来る)。

私ができることは、DBマシンへの読み取り/書き込みアクセス権とサーバーマシンへの読み取りアクセス権を持つ第三者が、ユーザーが作成したレコードを追加/変更することを非常に困難にすることです。削除については、これを行います。プログラムは実際の更新/削除操作を行いません。すべての更新/削除は単にデータの新しいバージョンを追加し、古いものを「古い」としてマークします。すべてのデータのハッシュは、改ざん防止バックアップに継続的に保存されます。これにより、古いデータの更新からも保護されます。私を保護できないのは、既存のユーザーを偽装して新しいデータを追加しないことだけです。

安全な送信にhttpsを使用します(SSL証明機関から購入した証明書を使用)。

「ユーザーに送信されるJavaScript」のようにサイトを実際に保護することはできないので、これは弱点です(誰かがJavaScriptコードにキーロガーを直接インストールする可能性があります)。私は見回りましたが、いくつかのJavaScriptコードに署名してクライアントに送信し、クライアントに署名をチェックさせることができないようです(おそらく、動的言語であるJavaScriptが悪意のあるJavaScriptに自分自身を挿入させるためです)署名されたコード/ JavaScriptベースライブラリのランダムな部分にあるため、既存の環境すべてをファイアウォールで保護することは非常に困難です)。サーバー側から署名を確認できます(サーバープログラムは署名されており、署名されたJavaScriptのみを送信します)。

クライアント側のSSL証明書はユーザーにとって使いにくいため、使用したくありません(ユーザーがコンピューターを変更した場合、ユーザーは証明書を再インストールする必要があります。ユーザーがコンピューターに証明書を忘れた場合、それを盗む可能性があります。 ...)

ECDsaを使用して、ユーザーパスワード(およびその他のデータ)から公開/秘密キーペアを生成し、クライアントがユーザーのデータにクライアント側で署名することを私が考えたソリューションです。公開/秘密鍵の生成はクライアント側で行われます。ユーザーが作成されてパスワードが選択されると、クライアントは公開/秘密鍵ペアを生成し、生成された公開鍵をサーバーに通知します。ユーザーはパスワードを覚えるだけで済みます。

明らかにこれの弱点は、誰かがユーザーの新しい公開鍵をサーバーに追加し、新しい公開鍵で何かに署名できることですが、新しい公開鍵があるため、これを見つけるのは非常に簡単です。より巧妙なことは、古い公開鍵を変更してから、ユーザーがその新しい鍵で署名したすべてのものを再署名することです。そのため、データが改ざんされたかどうかを示すことは不可能ですが、これには改ざん防止ログがあります。

もう1つの弱点はユーザー側からです。誰かがキーロガーをインストールしてパスワードを盗む可能性がありますが、これはすべての「標準」パスワードスキームの問題です(このためにTOTP認証を追加します。最後に参照してください)。

パスワードの回復は「手動」で処理されます(スーパーユーザーはユーザーの身元を確認し、スーパーユーザーのキーでパスワードの変更に署名する必要があります)

次に、少し複雑にします。秘密キーは、各サーバーに固有のソルト(サーバーから送信されます)のPBKDF2とユーザーのパスワードから生成されます。残念ながら、ソフトウェアを携帯電話と互換性を持たせるには、PBKDF2の反復を低く保つ必要があります(mmmh ...古いOptimus Wでは、1000回の反復には8秒必要ですが、S3の場合はほぼ瞬時です...しかし、1000回の反復はありませんそれほど強くない)(おそらく、PBKDF2の代わりにScryptを使用できます... GPU攻撃に対してより耐性があるはずです)

つまり、最終的には次のようになります。

ユーザーはユーザー名とパスワードを挿入し、ボタンを押します。クライアントはサーバーにソルト、ハッシュ関数の反復回数、および時刻(これは同じ署名の再利用に基づいて攻撃を停止するため)を要求し、PBKDF2/Scryptを使用してパスワードのハッシュを計算します、ECC秘密鍵を再生成し、メッセージ(要求された操作とサーバーが受信した時刻を含む)に署名し、署名を送信します。サーバーは、彼がどのような課題を与え、何が返答されたかを記憶する必要があります(したがって、「使い果たされています」)。

この後、2つのステップの検証を追加できます(たとえば、Google認証システムで使用されるアルゴリズムを使用)。このキーは、ユーザーとサーバー間で共有されます。ワンタイムパスワードは、クライアントが署名したさまざまなメッセージに挿入できます。サーバーはTOTPの計算時間を節約できるため、後で簡単に確認できます。

だから問題は:すべて大丈夫ですか?すべてを行う既製のソリューションはありますか?私の推論に穴はありますか?

6
xanatos

DBバックエンドは「安全ではありません」。データを改ざんすることは可能です(多くの人がマシンにアクセスでき、おそらく「クラウド内」にある)[...]

私ができることは、DBマシンへの読み取り/書き込みアクセス権を持つサードパーティにとって非常に困難にすることです[...]

あなたの目標はそれを作ることであってはなりません非常に難しい第三者があなたのデータベースからデータを変更することは。あなたの目標は、管理者以外の誰もがサーバーとデータベースの両方にアクセスできないようにすることです。

今あなたがしていることは、あなたの銀行口座番号とパスワードを知らない人に完成させて、それらの知らない人があなたのお金を取るのをどのように困難にするのかを尋ねるようなものです。そもそも、アカウント情報を共有しないことを考えているかもしれません。

また、「クラウド内」がセキュリティとどのように関係しているかも不明です。 AmazonやMicrosoftなどのほとんどのクラウドプロバイダーは、非常に安全な方法で仮想マシンをホストするという優れた仕事をします。

したがって:

  • suアクセスでサーバーをSSH接続できる「サードパーティ」を排除します。これは、Webアプリケーションをホストする間違った方法です。そんなことしないで。その場合は、ウェブサイトのユーザーに、提供したすべての個人情報を完全な見知らぬ人と共有できること、および共有することを伝えてください。

  • TLSを使用します。特に無料のサービスが存在するため、これを使用しない理由はありません。

  • クライアント側を信頼しないでください。いいえ、JavaScriptに署名することはできません。一般に、クライアント側では、ユーザーを自分自身から保護したり、ユーザーがマシンにインストールしたがらくたから保護したりすることはできません。ウイルスはブラウザに自分自身を挿入し、JavaScriptを変更することができます。 JavaScriptが改ざんされているかどうかをチェックするメカニズムを実行すると、チェックメカニズム自体が改ざんされる可能性があります。

  • クライアント側で情報を暗号化することはできますが、実際に暗号化を行ういくつかのケースに限定される正当な理由はいくつかあります。その理由は、繰り返しになりますが、ユーザーがデバイスを保護することは通常難しいため、クライアントマシンは信頼されるべきではないからです。一方、サーバーは非常に簡単に保護できます。TLSを使用すると、中間者攻撃を効果的に防止できます。

したがって、サーバーとサーバーとクライアント間の通信の両方が安全であることを確認してください。

いくつかのメモ:

悲しいことに、ソフトウェアを携帯電話と互換性を持たせるには、PBKDF2の反復を低く保つ必要があります[...](おそらく、PBKDF2の代わりにScryptを使用できます... GPU攻撃に対してより耐性があるはずです)。

これが、ハッシュサーバー上を計算する必要がある理由です。反復回数を減らすと、攻撃者がハッシュをブルートフォースで攻撃しやすくなります。

別のアルゴリズムを検索することは、ここでは間違った解決策です。攻撃者willには強力なCPUとGPUがあることに注意してください。あなたの目標は攻撃者を遅くすることです、そしてあなたは反復を増やすことによってそれをします。

この後、2つのステップの検証を追加できます(たとえば、Google認証システムで使用されるアルゴリズムを使用)。このキーは、ユーザーとサーバー間で共有されます。

これは、「サードパーティ」がこれらのキーに完全にアクセスできることを意味します。このコンテキストでは、2段階認証は事態をさらに悪化させます:それはあなたに安心感を与えますが、まったく利点はありません。

4

答えがないので、制約を完全に理解していなくても、大胆に提案します。

まず、あなたの質問には間違いが含まれています。セキュリティ証明書を「購入」する必要はありません。 StartSSL(StartComが提供)は無料で、Let's Encrypt( https://letsencrypt.org )は無料です。他にもあります。

しかし、TLSやその他の証明書ベースの非対称暗号化技術を使用して特定の形式のセキュリティを提供したくない場合は、共有シークレットを使用して対称暗号化/復号化を行ってみませんか?

シークレットを共有するには、Diffie-Hellmanアルゴリズムを使用します(ただし、中間者攻撃から保護するためのルックアップ方法)。 JSとPHP(githubのTightConnect))の実装は、デモとして利用できます( http://www.springtimesoftware.com/tightconnect/demo/ )。

0
David Spector