web-dev-qa-db-ja.com

クライアント証明書に自己署名して配布する場合、次の手順は適切ですか?

次のようなケースがあります。

  1. インターネット(つまり、信頼できないチャネル)には多数のクライアントがあり、最初は数百人ですが、数は増えています。
  2. これらのクライアントに関連する処理を行うサーバーがあります。この関係は、他の場所、たとえばWebポータルの前に確立されます。
  3. クライアントは、インターネットを介してソフトウェア(ブラウザなどではなく人間が操作する)を介してサーバーに接続し、チャンネルを暗号化してサーバーがどのクライアントが接続されているかを認識できるように素材をロードできる必要があります。
  4. 接続が確立され、資料が送信されたときに、クライアントが資料を要求していないと主張する可能性のある問題はないはずです。 彼らが受け取ったときに資料を受け取らないことに関するトーマスの質問に関連する編集として:私がここでプレーンパスワードを使用した場合、証明書およびそれを使用する他の誰かよりも簡単にパスワードが漏洩する危険がありますか?転送する資料を入手しますか?ただし、この「シーケンスID」(次のリストのポイント6を参照)を使用して、このような状況を緩和することを検討しました。これは、おそらく証明書の有無にかかわらず役立ちます。
  5. クライアントは着信接続を受け入れません。この既知のサーバーに対してそれらを開始するだけです。
  6. 通常、クライアントを操作するクライアントには、認証局から発行された独自の証明書はありません。
  7. サーバープロセッサプログラムには、認証局(Thawteなど)によって発行された証明書があります。

質問:これを安全で保守可能な方法で達成するための良い方法は何でしょうか?

私の知る限り、使用できるPKIソフトウェアはありません。私は以下を計画しました:

  1. クライアントに、たとえばポータルから転送ソフトウェアをダウンロードさせます。ポータルには、なんらかのクライアントIDを含む設定ファイルを含めることができます(たとえば、ワンタイムパスワードはポイント4を参照)。
  2. クライアントがサーバーに転送ソフトウェアをインストールすると、クライアントIDがCNにある自己署名証明書が生成されます。たとえば、makecert -r -n "CN=SomeClientId" -pe -ss myです。
  3. このソフトウェアは、生成された証明書の拇印をクライアントIDとともにサーバーに送信し、他の場所で取得したワンタイムパスワードを使用します(ポイント1を参照)。
  4. サーバーは、クライアントIDとともに拇印を格納します。
  5. これで、転送ソフトウェアがサーバーに接続すると、送信された拇印を介してそれがどのクライアントに属しているかを確認でき、チャネルが保護されます。
  6. セキュリティを強化するために、サーバーは、それぞれの転送クライアントのシーケンス番号と一致する必要があるシーケンス番号を維持します。同期が取れていない場合は違反が疑われ、少なくともクライアントがポータルにアクセスしてカウンターをリセットし、転送ソフトウェアでリセットする必要があります(たとえば、設定ファイルでset 0を設定します)。

これはサウンドアレンジのように見えますか?もっと良いものがありますか?特定のクライアントのアクセスを拒否する必要がある場合は、サーバーデータベースにフラグを設定して、特定の拇印が許可されなくなったことを示すだけでよいようです。 SEを参照しているときに、 秘密キーを公開せずにクライアント証明書を配布する方法を知りましたか?Thomas Pornin's の答えからヒントを得て、このプロセスを変更して、証明書を生成するときに変更できることを確認しました。例として:

  1. 適切なパラメーターを使用してsomeclient.infファイルを作成します(Windowsの場合、それ以外の場合は、opensslを使用するなど)。
  2. certreq -new someclient.inf request.csrを実行して、リクエストファイルを作成します。
  3. ワンタイムパスワードを使用してcsrをサーバーに送信します。
  4. サーバーはcsrファイルを受信して​​証明書を作成し、拇印を保存して、証明書を送り返します。
  5. クライアントはオプションで、certreq -accept someclient.cerを使用して証明書をインストールします。

別の質問:これは、最初に概説した手順を超えて追加の利点をもたらしますか(これは適切な手順ですか)?

追加の質問:サーバーが署名をどのように行うべきかについては不明です。どのプログラム?どのパラメータを使用しますか?しかし、この手順が使用可能なものである場合、おそらくこれらは別の質問になるはずです。

注:コマンドラインですべてのソフトウェアにアクセスできないか、クライアントエンドでコードの記述が複雑になる可能性があるため、おそらく BouncyCastle

4
Veksi

あなたのポイント4は少し不明確です:クライアントが「マテリアル」を受け取らなかったと主張し始めたのに問題はありましたが、実際には受けましたか?

notが問題である場合、基本的に必要なのは次のとおりです。

  • サーバーへのSSL接続。サーバーの証明書は、クライアントが有効であることを認識できる必要があります。クライアントソフトウェアはあなたの管理下にあるため、外部の商用CA(Thawteなど)からの証明書は必要ありません。必要なのは、クライアントソフトウェアによって受け入れられる証明書です。クライアントコードに証明書のコピーを埋め込み、クライアントが、サーバーから送信された証明書が期待されるものとビットごとに等しいことを確認する限り、サーバー用に独自の自己署名証明書を作成できます。 。

  • 一部のクライアント固有のシークレット値[〜#〜] s [〜#〜]クライアント側に保存されます。この値は一種のパスワードと考えることができますが、操作に人間の脳は関与していないため、ランダムに均一に生成されるstrong-たとえば、任意の128ビット文字列にすることができます。クライアントは[〜#〜] s [〜#〜]を保存し、サーバーはh(S)を保存します(一部のハッシュ関数の場合h() =)。

  • クライアントが接続すると、SSL接続を介してサーバーに[〜#〜] s [〜#〜]を送信します。サーバーはh(S)を計算し、データベースで検索して、接続されているクライアントを確認します。

このモデルでは、クライアント側の証明書を追加する必要はありません。あなたはcanですが、それはセキュリティモデルに追加の利点をもたらしません。クライアント側の証明書を使用する理由の1つは、証明書用に設計されたハードウェア要素(スマートカード)と相互運用することです。ソフトウェア側にいる限り、単純な秘密の値がトリックを実行します(いずれの場合も、クライアントhasは、秘密の値(証明書を所有している場合は秘密鍵など)を格納するために使用します) )。

2
Thomas Pornin