Servidor Proxy HTTPS en node.js

Estoy desarrollando una aplicación de servidor proxy node.js y quiero que admita los HTTP y HTTPS(SSL) (como servidor).

Actualmente estoy usando el node-http-proxy esta manera:

 const httpProxy = require('http-proxy'), http = require('http'); var server = httpProxy.createServer(9000, 'localhost', function(req, res, proxy) { console.log(req.url); proxy.proxyRequest(req, res); }); http.createServer(function(req, res) { res.end('hello!'); }).listen(9000); server.listen(8000); 

Configuré mi navegador para usar el proxy HTTP en localhost:8000 y funciona. También quiero capturar las solicitudes HTTPS (es decir, configurar mi navegador para usar localhost:8000 como proxy HTTPS también y capturar las solicitudes en mi aplicación). ¿Podrías ayudarme por favor cómo puedo hacer eso?

PS :

Si me suscribo al evento de upgrade del objeto httpProxy server, puedo obtener las solicitudes pero no sé cómo reenviar la solicitud y enviar la respuesta al cliente:

 server.on('upgrade', function(req, socket, head) { console.log(req.url); // I don't know how to forward the request and send the response to client }); 

Cualquier ayuda sería apreciada.

Las soluciones apenas existen para esto, y la documentación es pobre en el mejor de los casos para admitir ambos en un servidor. El truco aquí es comprender que las configuraciones de proxy del cliente pueden enviar solicitudes https a un servidor proxy http. Esto es cierto para Firefox si especifica un proxy HTTP y luego marca “igual para todos los protocolos”.

Puede manejar las conexiones https enviadas a un servidor HTTP escuchando el evento “conectar”. Tenga en cuenta que no tendrá acceso al objeto de respuesta en el evento de conexión, solo el zócalo y la cabeza del cuerpo. Los datos enviados a través de este socket permanecerán encriptados como el servidor proxy.

En esta solución, no tiene que crear sus propios certificados y, como resultado, no tendrá conflictos de certificados. El tráfico simplemente se procesa, no se intercepta y se reescribe con certificados diferentes.

 // Install npm dependencies first // npm init // npm install --save [email protected] // npm install --save [email protected] var httpProxy = require("http-proxy"); var http = require("http"); var url = require("url"); var net = require('net'); var server = http.createServer(function (req, res) { var urlObj = url.parse(req.url); var target = urlObj.protocol + "//" + urlObj.host; console.log("Proxy HTTP request for:", target); var proxy = httpProxy.createProxyServer({}); proxy.on("error", function (err, req, res) { console.log("proxy error", err); res.end(); }); proxy.web(req, res, {target: target}); }).listen(8080); //this is the port your clients will connect to var regex_hostport = /^([^:]+)(:([0-9]+))?$/; var getHostPortFromString = function (hostString, defaultPort) { var host = hostString; var port = defaultPort; var result = regex_hostport.exec(hostString); if (result != null) { host = result[1]; if (result[2] != null) { port = result[3]; } } return ( [host, port] ); }; server.addListener('connect', function (req, socket, bodyhead) { var hostPort = getHostPortFromString(req.url, 443); var hostDomain = hostPort[0]; var port = parseInt(hostPort[1]); console.log("Proxying HTTPS request for:", hostDomain, port); var proxySocket = new net.Socket(); proxySocket.connect(port, hostDomain, function () { proxySocket.write(bodyhead); socket.write("HTTP/" + req.httpVersion + " 200 Connection established\r\n\r\n"); } ); proxySocket.on('data', function (chunk) { socket.write(chunk); }); proxySocket.on('end', function () { socket.end(); }); proxySocket.on('error', function () { socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n"); socket.end(); }); socket.on('data', function (chunk) { proxySocket.write(chunk); }); socket.on('end', function () { proxySocket.end(); }); socket.on('error', function () { proxySocket.end(); }); }); 

He creado un proxy http / https con la ayuda del módulo http-proxy : https://gist.github.com/ncthis/6863947

Código a partir de ahora:

 var fs = require('fs'), http = require('http'), https = require('https'), httpProxy = require('http-proxy'); var isHttps = true; // do you want a https proxy? var options = { https: { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('key-cert.pem') } }; // this is the target server var proxy = new httpProxy.HttpProxy({ target: { host: '127.0.0.1', port: 8080 } }); if (isHttps) https.createServer(options.https, function(req, res) { console.log('Proxying https request at %s', new Date()); proxy.proxyRequest(req, res); }).listen(443, function(err) { if (err) console.log('Error serving https proxy request: %s', req); console.log('Created https proxy. Forwarding requests from %s to %s:%s', '443', proxy.target.host, proxy.target.port); }); else http.createServer(options.https, function(req, res) { console.log('Proxying http request at %s', new Date()); console.log(req); proxy.proxyRequest(req, res); }).listen(80, function(err) { if (err) console.log('Error serving http proxy request: %s', req); console.log('Created http proxy. Forwarding requests from %s to %s:%s', '80', proxy.target.host, proxy.target.port); }); 

Aquí está mi solución de dependencias de NO (bibliotecas de sistema NodeJS puras):

 const http = require('http') const port = process.env.PORT || 9191 const net = require('net') const url = require('url') const requestHandler = (req, res) => { // discard all request to proxy server except HTTP/1.1 CONNECT method res.writeHead(405, {'Content-Type': 'text/plain'}) res.end('Method not allowed') } const server = http.createServer(requestHandler) const listener = server.listen(port, (err) => { if (err) { return console.error(err) } const info = listener.address() console.log(`Server is listening on address ${info.address} port ${info.port}`) }) server.on('connect', (req, clientSocket, head) => { // listen only for HTTP/1.1 CONNECT method console.log(clientSocket.remoteAddress, clientSocket.remotePort, req.method, req.url) if (!req.headers['proxy-authorization']) { // here you can add check for any username/password, I just check that this header must exist! clientSocket.write([ 'HTTP/1.1 407 Proxy Authentication Required', 'Proxy-Authenticate: Basic realm="proxy"', 'Proxy-Connection: close', ].join('\r\n')) clientSocket.end('\r\n\r\n') // empty body return } const {port, hostname} = url.parse(`//${req.url}`, false, true) // extract destination host and port from CONNECT request if (hostname && port) { const serverErrorHandler = (err) => { console.error(err.message) if (clientSocket) { clientSocket.end(`HTTP/1.1 500 ${err.message}\r\n`) } } const serverEndHandler = () => { if (clientSocket) { clientSocket.end(`HTTP/1.1 500 External Server End\r\n`) } } const serverSocket = net.connect(port, hostname) // connect to destination host and port const clientErrorHandler = (err) => { console.error(err.message) if (serverSocket) { serverSocket.end() } } const clientEndHandler = () => { if (serverSocket) { serverSocket.end() } } clientSocket.on('error', clientErrorHandler) clientSocket.on('end', clientEndHandler) serverSocket.on('error', serverErrorHandler) serverSocket.on('end', serverEndHandler) serverSocket.on('connect', () => { clientSocket.write([ 'HTTP/1.1 200 Connection Established', 'Proxy-agent: Node-VPN', ].join('\r\n')) clientSocket.write('\r\n\r\n') // empty body // "blindly" (for performance) pipe client socket and destination socket between each other serverSocket.pipe(clientSocket, {end: false}) clientSocket.pipe(serverSocket, {end: false}) }) } else { clientSocket.end('HTTP/1.1 400 Bad Request\r\n') clientSocket.destroy() } }) 

Probé este código con la configuración de Proxy de Firefox (¡incluso me pide el nombre de usuario y la contraseña!). Ingresé la dirección IP de la máquina donde se ejecuta este código y el puerto 9191 como se puede ver en el código. También configuro “Usar este servidor proxy para todos los protocolos”. Ejecuto este código localmente y en VPS – ¡en ambos casos funciona!

Puedes probar tu proxy NodeJS con curl:

 curl -x http://username:[email protected]:9191 https://www.google.com/ 

Los documentos de nodo-http-proxy contienen ejemplos de esto. Busque “Proxying to HTTPS from HTTPS” en https://github.com/nodejitsu/node-http-proxy El proceso de configuración es ligeramente diferente en cada navegador. Algunos tienen la opción de usar la configuración de su proxy para todos los protocolos; Algunos necesitas configurar el proxy SSL por separado.