Ich habe Code:
var r = require('request');
r({
method: 'POST',
url: 'https://api.dropbox.com'},
function() { console.log(arguments) } )
Wenn ich es mit Node 0.9.4 auf dem Desktop ausführe, wird dies in der Konsole angezeigt:
{ '0': [Error: Hostname/IP doesn't match certificate's altnames] }
Wenn ich es auf Netbook mit Node 0.6.12 ausführe, funktioniert alles ohne Fehler (302 Antwort - ich denke, es ist richtig).
In Frage Node.js Hostname / IP stimmt nicht mit den Altnamen der Zertifikate überein . Rojuinex schreibt: "Ja, Browserproblem ... Entschuldigung". Was bedeutet "Browserproblem"?
UPD. Dieses Problem wurde nach dem Rollback auf Node v0.8 behoben
Antworten:
Seit 0.9.2 (einschließlich 0.10.x) validiert node.js jetzt standardmäßig Zertifikate. Aus diesem Grund kann es beim Upgrade auf node.js 0.8 strenger werden. (HT: https://github.com/mscdex/node-imap/issues/181#issuecomment-14781480 )
Sie können dies mit der
{rejectUnauthorized:false}
Option vermeiden , dies hat jedoch schwerwiegende Auswirkungen auf die Sicherheit . Alles, was Sie an den Peer senden, wird weiterhin verschlüsselt, aber es wird viel einfacher, einen Man-in-the-Middle-Angriff durchzuführen, dh Ihre Daten werden an den Peer verschlüsselt, aber der Peer selbst ist nicht der Server, von dem Sie glauben, dass er es ist!Es ist besser, zuerst zu diagnostizieren, warum das Zertifikat nicht autorisiert ist, und zu prüfen, ob dies stattdessen behoben werden kann.
quelle
tls.connect({host: host, port: 443, rejectUnauthorized: false});
rejectUnauthorized
deaktiviert SSL nicht, deaktiviert jedoch die Überprüfung von Serverzertifikaten. Das Bereitstellen eines Rückrufs, der alle Server überprüft, scheint ungefähr gleich zu sein, nicht wahr?checkServerIdentity() {}
nur einen Teil der Prüfungen deaktivieren, aber nicht alle? Das heißt, wenn man die TLS-Verbindung voll ausnutzen will, muss man sicherstellen, dass sie vollständig validiert ist! Wenn es sich beispielsweise um ein bekanntes Zertifikat handelt, fügen Sie Code hinzu,checkServerIdentity
um es zu pinnen .Eine leicht aktualisierte Antwort (da ich unter verschiedenen Umständen auf dieses Problem gestoßen bin.)
Wenn Sie über SSL eine Verbindung zu einem Server herstellen, legt der Server zunächst ein Zertifikat mit der Aufschrift "Ich bin api.dropbox.com" vor. Das Zertifikat hat einen "Betreff" und der Betreff einen "CN" (kurz für "Common Name"). Das Zertifikat kann auch einen oder mehrere "subjectAltNames" haben. Wenn node.js eine Verbindung zu einem Server herstellt, ruft node.js dieses Zertifikat ab und überprüft dann, ob der Domänenname, zu dem eine Verbindung hergestellt werden soll (api.dropbox.com), entweder mit dem CN des Betreffs oder einem der Altnamen übereinstimmt. Beachten Sie, dass in Knoten 0.10.x, wenn Sie eine Verbindung über eine IP herstellen, die IP-Adresse in den Altnamen angegeben werden muss - node.js versucht nicht, die IP anhand des CN zu überprüfen.
Wenn Sie das
rejectUnauthorized
Flag auf "false" setzen, wird diese Prüfung umgangen. Erstens, wenn der Server Ihnen andere Anmeldeinformationen als erwartet gibt, ist etwas faul, und zweitens werden auch andere Prüfungen umgangen - es ist keine gute Idee, wenn Sie dies tun Ich verbinde mich über das Internet.Wenn Sie node> = 0.11.x verwenden, können Sie auch eine
checkServerIdentity: function(host, cert)
Funktion für das tls-Modul angeben , die zurückgegeben werden soll,undefined
wenn Sie die Verbindung zulassen und andernfalls eine Ausnahme auslösen möchten (obwohl ich nicht weiß, obrequest
dieses Flag als Proxy verwendet wird Es kann praktisch sein, eine solche Funktion zu deklarieren undconsole.log(host, cert);
herauszufinden, was zum Teufel los ist.quelle
undefined
vom Rückruf der Serveridentität die Sicherheit so stark verbessert, aber das ist nicht das, was diese Antwort vorschlägt, iiuc. +1 auf den Vorschlag, die Informationen zum Debuggen zu protokollieren (und dann Code zu schreiben, um sie sorgfältig "von Hand" zu überprüfen, wenn das Serverzertifikat und / oder der CA-Speicher des Clients absolut nicht repariert werden können).So beheben Sie das Problem für das Paket http-proxy
1) HTTP (localhost) greift auf HTTPS zu Um dieses Problem zu beheben, setzen Sie changeOrigin auf true.
const proxy = httpProxy.createProxyServer(); proxy.web(req, res, { changeOrigin: true, target: https://example.com:3000, });
2) HTTPS Zugriff auf HTTPS Sie sollten ein SSL-Zertifikat einschließen
httpProxy.createServer({ ssl: { key: fs.readFileSync('valid-ssl-key.pem', 'utf8'), cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8') }, target: 'https://example.com:3000', secure: true }).listen(443);
quelle
Ich hatte das gleiche Problem bei der Verwendung des Anforderungsmoduls zum Proxy von POST-Anforderungen von einem anderen Ort. Dies lag daran, dass ich die Host-Eigenschaft im Header belassen habe (ich habe den Header von der ursprünglichen Anforderung kopiert).
quelle
Ich weiß, das ist alt, ABER für alle anderen, die suchen:
Entfernen Sie https: // aus dem Hostnamen und fügen Sie stattdessen Port 443 hinzu.
{ method: 'POST', hostname: 'api.dropbox.com', port: 443 }
quelle
Nachdem überprüft wurde, ob das Zertifikat von einer bekannten Zertifizierungsstelle ausgestellt wurde, werden die alternativen Antragstellernamen oder der allgemeine Name überprüft, um sicherzustellen, dass der Hostname übereinstimmt. Dies ist in der Funktion checkServerIdentity . Wenn das Zertifikat alternative Betreffnamen enthält und der Hostname nicht aufgeführt ist, wird die beschriebene Fehlermeldung angezeigt:
Wenn Sie über das CA-Zertifikat verfügen, mit dem das von Ihnen verwendete Zertifikat generiert wird (normalerweise bei Verwendung von selbstsignierten Zertifikaten), kann dies bereitgestellt werden
var r = require('request'); var opts = { method: "POST", ca: fs.readFileSync("ca.cer") }; r('https://api.dropbox.com', opts, function (error, response, body) { // do something });
Dadurch wird überprüft, ob das Zertifikat von der bereitgestellten Zertifizierungsstelle ausgestellt wurde. Die Überprüfung des Hostnamens wird jedoch weiterhin durchgeführt. Die Angabe der Zertifizierungsstelle reicht aus, wenn das Zertifikat den Hostnamen in den alternativen Betreffnamen enthält. Wenn dies nicht der Fall ist und Sie auch die Überprüfung des Hostnamens überspringen möchten, können Sie eine Noop-Funktion für übergeben
checkServerIdentity
var r = require('request'); var opts = { method: "POST", ca: fs.readFileSync("ca.cer"), agentOptions: { checkServerIdentity: function() {} } }; r('https://api.dropbox.com', opts, function (error, response, body) { // do something });
quelle
Die andere Möglichkeit, dies unter anderen Umständen zu beheben, besteht darin, es
NODE_TLS_REJECT_UNAUTHORIZED=0
als Umgebungsvariable zu verwendenNODE_TLS_REJECT_UNAUTHORIZED=0 node server.js
WARNUNG: Dies ist aus Sicherheitsgründen eine schlechte Idee
quelle
{rejectUnauthorized:false}
Option und birgt auch erhebliche Sicherheitsbedenken.Wir haben dieses Problem nicht, wenn wir unsere Clientanforderung mit der
localhost
Zieladresse (host
oderhostname
auf node.js) testen und unser allgemeiner ServernameCN = localhost
im Serverzertifikat enthalten ist. Aber selbst wenn wirlocalhost
für127.0.0.1
oder eine andere IP ändern, erhalten wir FehlerHostname/IP doesn't match certificate's altnames
auf node.js oderSSL handshake failed
auf QT.Ich hatte das gleiche Problem mit meinem Serverzertifikat auf meiner Client-Anfrage. Um es auf meiner Client Node.js App zu lösen, musste ich eine mit dem folgenden Wert
subjectAltName
auf meine setzenserver_extension
:[ server_extension ] . . . subjectAltName = @alt_names_server [alt_names_server] IP.1 = x.x.x.x
und dann verwende ich,
-extension
wenn ich das Zertifikat erstelle und signiere.Beispiel:
In meinem Fall exportiere ich zuerst die Konfigurationsdatei des Ausstellers, da diese Datei Folgendes enthält
server_extension
:export OPENSSL_CONF=intermed-ca.cnf
Also erstelle und signiere ich mein Serverzertifikat:
openssl ca \ -in server.req.pem \ -out server.cert.pem \ -extensions server_extension \ -startdate `date +%y%m%d000000Z -u -d -2day` \ -enddate `date +%y%m%d000000Z -u -d +2years+1day`
zum Beispiel:
CN = 127.0.0.1
quelle
Wenn Sie einer Subdomain vertrauen möchten, z. B. aaa.localhost, machen Sie es bitte nicht so
mkcert localhost *.localhost 127.0.0.1
, dies funktioniert nicht, da einige Browser keine Wildcard-Subdomain akzeptieren.Vielleicht versuchen
mkcert localhost aaa.localhost 127.0.0.1
.quelle
Ich habe dies beim Streaming von einer Lambda-Funktion in AWS zu ElasticSearch erhalten. Ich schlug meinen Kopf gegen eine Wand und versuchte es herauszufinden. Am Ende beim Einstellen von
request.headers['Host']
Ich habe in derhttps://
Domain für ES hinzugefügt - das Ändern in[es-domain-name].eu-west-1.es.amazonaws.com
(ohne https: //) hat sofort funktioniert. Unten ist der Code, den ich verwendet habe, um es zum Laufen zu bringen. Hoffentlich kann jeder andere seinen Kopf gegen eine Wand schlagen ...import path from 'path'; import AWS from 'aws-sdk'; const { region, esEndpoint } = process.env; const endpoint = new AWS.Endpoint(esEndpoint); const httpClient = new AWS.HttpClient(); const credentials = new AWS.EnvironmentCredentials('AWS'); /** * Sends a request to Elasticsearch * * @param {string} httpMethod - The HTTP method, e.g. 'GET', 'PUT', 'DELETE', etc * @param {string} requestPath - The HTTP path (relative to the Elasticsearch domain), e.g. '.kibana' * @param {string} [payload] - An optional JavaScript object that will be serialized to the HTTP request body * @returns {Promise} Promise - object with the result of the HTTP response */ export function sendRequest ({ httpMethod, requestPath, payload }) { const request = new AWS.HttpRequest(endpoint, region); request.method = httpMethod; request.path = path.join(request.path, requestPath); request.body = payload; request.headers['Content-Type'] = 'application/json'; request.headers['Host'] = '[es-domain-name].eu-west-1.es.amazonaws.com'; request.headers['Content-Length'] = Buffer.byteLength(request.body); const signer = new AWS.Signers.V4(request, 'es'); signer.addAuthorization(credentials, new Date()); return new Promise((resolve, reject) => { httpClient.handleRequest( request, null, response => { const { statusCode, statusMessage, headers } = response; let body = ''; response.on('data', chunk => { body += chunk; }); response.on('end', () => { const data = { statusCode, statusMessage, headers }; if (body) { data.body = JSON.parse(body); } resolve(data); }); }, err => { reject(err); } ); }); }
quelle
Für Entwickler, die die Fetch-API in einer Node.js-App verwenden, ist dies der Grund , warum dies mit reverseUnauthorized funktioniert .
Beachten Sie, dass die Verwendung
rejectUnauthorized
gefährlich ist, da sie potenzielle Sicherheitsrisiken birgt, da sie ein problematisches Zertifikat umgeht.const fetch = require("node-fetch"); const https = require('https'); const httpsAgent = new https.Agent({ rejectUnauthorized: false, }); async function getData() { const resp = await fetch( "https://myexampleapi.com/endpoint", { agent: httpsAgent, }, ) const data = await resp.json() return data }
quelle