22

自己署名証明書を使用してNode.js0.8.8を使用してTLSサーバー/クライアントセットアップを作成しようとしています。

重要なサーバーコードは次のようになります

var tlsServer = tls.createServer({
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem')
}, function (connection) {
  // [...]
});
tlsServer.listen(3000);

このサーバーに接続しようとすると、次のコードを使用します。

var connection = tls.connect({
  host: '192.168.178.31',
  port: 3000,

  rejectUnauthorized: true,
  ca: [ fs.readFileSync('server-cert.pem') ]
}, function () {
  console.log(connection.authorized);
  console.log(connection.authorizationError);
  console.log(connection.getPeerCertificate());
});

行を削除すると

ca: [ fs.readFileSync('server-cert.pem') ]

クライアント側のコードから、Node.jsは私に通知するエラーをスローしますDEPTH_ZERO_SELF_SIGNED_CERT。私が理解している限り、これは自己署名証明書であり、この証明書を信頼する他の当事者がいないという事実によるものです。

削除した場合

rejectUnauthorized: true,

同様に、エラーはなくなりました-しかし、これconnection.authorizedfalse事実上、私の接続が暗号化されていないことを意味します。とにかく、getPeerCertificate()私を使用してサーバーから送信された証明書にアクセスできます。暗号化された接続を強制したいので、この行を削除できない可能性があることを理解しています。

caこれで、このプロパティを使用して、Node.jsに信頼させたいCAを指定できることを読みました。TLSモジュールのドキュメントは、サーバー証明書をcaアレイに追加するだけで十分であり、すべてが正常であることを示しています。

そうすれば、このエラーはなくなりますが、新しいエラーが発生します。

Hostname/IP doesn't match certificate's altnames

私にとってこれは、CAが基本的に信頼されていることを意味します。したがって、これで問題ありませんが、証明書は、私が使用しているホストとは別のホスト用に作成されました。

を使用して証明書を作成しました

$ openssl genrsa -out server-key.pem 2048
$ openssl req -new -key server-key.pem -out server-csr.pem
$ openssl x509 -req -in server-csr.pem -signkey server-key.pem -out server-cert.pem

ドキュメントが示すように。CSRを作成するとき、国、州、...、一般名(CN)などの通常の質問があります。SSL証明書について「Web上で」と言われるので、CNとして名前を指定するのではなく、使用するホスト名を指定します。

そして、これはおそらく私が失敗するところです。

私は試した

  • localhost
  • 192.168.178.31
  • eisbaer
  • eisbaer.fritz.box

ここで、最後の2つは、私のマシンのローカル名と完全修飾ローカル名です。

私がここで間違っていることについて何か考えはありますか?

4

5 に答える 5

9

tls.jsの 112 ~ 141 行目で、呼び出し時に使用されるホスト名connectが IP アドレスの場合、証明書の CN が無視され、SAN のみが使用されていることがわかります。

私の証明書は SAN を使用していないため、検証に失敗します。

于 2012-12-30T08:16:27.753 に答える
7

ホスト名を使用して接続している場合、ホスト名は DNS タイプのサブジェクト代替名に対してチェックされます (存在する場合)。そうでない場合は、サブジェクト識別名の CN にフォールバックします。

接続に IP アドレスを使用している場合、IP アドレスは、CN にフォールバックすることなく、IP アドレスタイプの SAN に対してチェックされます。

これは少なくとも、HTTP over TLS仕様 (すなわち HTTPS) に準拠した実装が行うことです。一部のブラウザはもう少し寛容です。

これはJava のこの回答とまったく同じ問題であり、OpenSSL 経由でカスタム SAN を配置する方法も提供します (このドキュメントも参照してください)。

一般的に言えば、テスト CA 以外では、IP アドレスに依存する証明書を管理するのは非常に困難です。ホスト名で接続する方が良いです。

于 2012-12-30T11:35:36.633 に答える
3

Mitar は、成功時に checkServerIdentity が「true」を返す必要があるという誤った仮定を持っていましたが、実際には成功時に「undefined」を返す必要があります。その他の値は、エラーの説明として扱われます。

したがって、そのようなコードは正しいです:

var options = {
  host: '192.168.178.31',
  port: 3000,
  ca: [ fs.readFileSync('server-cert.pem') ],
  checkServerIdentity: function (host, cert) {
    // It can be useful to resolve both parts to IP or to Hostname (with some synchronous resolver (I wander why they did not add done() callback as the third parameter)).
    // Be carefull with SNI (when many names are bound to the same IP).
    if (host != cert.subject.CN)
      return 'Incorrect server identity';// Return error in case of failed checking.
      // Return undefined value in case of successful checking.
      // I.e. you could use empty function body to accept all CN's.
  }
};
options.agent = new https.Agent(options);
var req = https.request(options, function (res) {
  //...
});

Mitarの回答を編集しようとしただけですが、編集が拒否されたので、別の回答を作成しました。

于 2016-01-27T20:07:09.103 に答える
-1

あなたが間違っているのは、ドメイン名の代わりに IP アドレスを使用していることです。ドメイン名を作成して DNS サーバー (または単にホスト ファイル) に貼り付け、ドメイン名を共通名として自己署名証明書を作成し、IP アドレスではなくドメイン名に接続します。

于 2012-12-30T08:45:17.363 に答える