http-proxy-middleware icon indicating copy to clipboard operation
http-proxy-middleware copied to clipboard

Failure to handle HTTPS requests

Open pwlerke opened this issue 8 years ago • 9 comments

Expected behavior

Expect successful SSL connection and response from the api server. Even though ssl object is being set in the options, it doesn't appear that the configuration is taking that into account. If ssl object is set, http requests are successfully proxied, but https requests are not. The same certificates and client configuration do work using http-proxy, rather than http-proxy-middleware.

Using http-proxy:

var fs = require('fs'),
    httpProxy = require('http-proxy');

httpProxy.createServer({
  ssl: {
    key: fs.readFileSync('./ssl.key'),
    cert: fs.readFileSync('./ssl.crt')
  },
  target: 'http://localhost:9000',
  secure: false
}).listen(3000);

$ curl -k https://localhost:3000/api -v

  • Trying 127.0.0.1...
  • Connected to localhost (127.0.0.1) port 3000 (#0)
  • ALPN, offering http/1.1
  • Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
  • error setting certificate verify locations, continuing anyway:
  • CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none
  • TLSv1.2 (OUT), TLS header, Certificate Status (22):
  • TLSv1.2 (OUT), TLS handshake, Client hello (1):
  • TLSv1.2 (IN), TLS handshake, Server hello (2):
  • NPN, negotiated HTTP1.1
  • TLSv1.2 (IN), TLS handshake, Certificate (11):
  • TLSv1.2 (IN), TLS handshake, Server key exchange (12):
  • TLSv1.2 (IN), TLS handshake, Server finished (14):
  • TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
  • TLSv1.2 (OUT), TLS change cipher, Client hello (1):
  • TLSv1.2 (OUT), TLS handshake, Unknown (67):
  • TLSv1.2 (OUT), TLS handshake, Finished (20):
  • TLSv1.2 (IN), TLS change cipher, Client hello (1):
  • TLSv1.2 (IN), TLS handshake, Finished (20):
  • SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
  • ALPN, server did not agree to a protocol
  • Server certificate:
  • subject: C=US; ST=VA; O=Internet Widgits Pty Ltd; CN=PWL
  • start date: Oct 29 15:47:22 2016 GMT
  • expire date: Oct 27 15:47:22 2026 GMT
  • issuer: C=US; ST=VA; O=Internet Widgits Pty Ltd; CN=PWL
  • SSL certificate verify result: self signed certificate (18), continuing anyway.

GET /api HTTP/1.1 Host: localhost:3000 User-Agent: curl/7.45.0 Accept: /

< HTTP/1.1 200 OK < content-type: text/plain < date: Fri, 09 Dec 2016 12:42:57 GMT < connection: close < transfer-encoding: chunked < request successfully proxied!

  • Closing connection 0
  • TLSv1.2 (OUT), TLS alert, Client hello (1):

Using http-proxy-middleware:

Actual behavior

$ curl -k https://localhost:3000/api -v

  • Trying 127.0.0.1...
  • Connected to localhost (127.0.0.1) port 3000 (#0)
  • ALPN, offering http/1.1
  • Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
  • error setting certificate verify locations, continuing anyway:
  • CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none
  • TLSv1.2 (OUT), TLS header, Certificate Status (22):
  • TLSv1.2 (OUT), TLS handshake, Client hello (1):
  • Unknown SSL protocol error in connection to localhost:3000
  • Closing connection 0 curl: (35) Unknown SSL protocol error in connection to localhost:3000

Setup

var fs      = require('fs');
var express = require('express');
var proxy   = require('http-proxy-middleware');

var apiProxy = proxy('/api', {
	ssl: {
		cert: fs.readFileSync('./ssl.crt'),
		key: fs.readFileSync('./ssl.key')
	},
	target: 'http://localhost:9000',
        changeOrigin: true,
        logLevel: 'info'
});

var app = express();
app.use(apiProxy);
app.listen(3000); 

pwlerke avatar Dec 09 '16 12:12 pwlerke

In your http-proxy setup secure: false option is set. In the http-proxy-middleware setup this option is missing.

Can you check again if you set the same options?

chimurai avatar Dec 09 '16 13:12 chimurai

Hi! I have a similar problem: here is my config with http-proxy-middleware

apiProxy = proxy('/',{
        target:'http://127.0.0.1:3000',
        ws:true,
        ssl: {
          key: fs.readFileSync('privkey.pem'),
          cert: fs.readFileSync('fullchain.pem')
        }
});
app.use(apiProxy);
app.listen(443);

and here is my config with http-proxy:

httpProxy.createServer({
  target: 'http://127.0.0.1:3000',
  ws:true,
  ssl: {
          key: fs.readFileSync('privkey.pem'),
          cert: fs.readFileSync('fullchain.pem')
  }
}).listen(443);

With http-proxy-middleware, I get the following error: gnutls_handshake() failed: The TLS connection was non-properly terminated.

KZARCA avatar Mar 05 '17 20:03 KZARCA

Not working with secure : false also ! Here is my config

const fs      = require('fs');
const express = require('express');
const proxy = require('http-proxy-middleware');

const app = express();
//running the app by serving the static files
//from dist folder
app.use(express.static(__dirname + '/dist'));

// Add middleware for http proxying 
const PRODUCTION_BACKEND_SERVER = 'http://10.98.4.122:8080';

const LOCAL_BACKEND_SERVER = 'http://localhost:8080';

//app.use('/mppkvvcl/nextgenbilling/', proxy({target: '', changeOrigin: true}));
app.use('/mppkvvcl/nextgenbilling/', proxy({
  ssl: {
		cert: fs.readFileSync('./ssl/ngbmpwincoin.jks'),
		key: fs.readFileSync('./ssl/KEY.txt')
	},
  target: PRODUCTION_BACKEND_SERVER,
  secure : false, 
  changeOrigin: true,
  logLevel: 'info'
}));

//for local testing
//app.use('/mppkvvcl/nextgenbilling/', proxy({target: LOCAL_BACKEND_SERVER, changeOrigin: true}));

const path = require('path');
// For all GET requests, send back index.html
// so that PathLocationStrategy can be used
app.get('/*', function(req, res) {
  res.sendFile(path.join(__dirname + '/dist/index.html'));
});

//starting app on default port or on heroku port
console.log("Starting Node Server with ngb frontend application");
let port = process.env.PORT || 443;
app.listen(port, () => {
    console.log("Started Server at port " + port);
});

ernitishkumar avatar Aug 30 '17 10:08 ernitishkumar

I run into this issue too. As I could verify, the plugin http-proxy-middleware initializes the http-proxy with a empty object [link] var proxy = httpProxy.createProxyServer({})

Looking at the http-proxy source code, it expects a ssl field to be present in the options object to make a switch between http and https connections link. I could not figure out how http-proxy-middleware is handling https connections since it seems to ignore the ssl field.

bsgiovanini avatar Jul 27 '18 13:07 bsgiovanini

the ssl field is not ignored.

with every request, a configuration object is constructed and passed to proxy.web https://github.com/chimurai/http-proxy-middleware/blob/952c1afb7045179417659cf45c111f51b9339d2e/lib/index.js#L41

your ssl configuration should be present: https://github.com/chimurai/http-proxy-middleware/blob/952c1afb7045179417659cf45c111f51b9339d2e/lib/index.js#L100

chimurai avatar Jul 27 '18 17:07 chimurai

I'm having the same issues. This is my index.js:

const express = require('@feathersjs/express')
const proxy = require('http-proxy-middleware')
const fs = require('fs')
const server = express()

const proxied = proxy({
    target: 'http://localhost:3000',
    ws: true,
    loglevel: 'debug',
    router: {
        'api.server.io': 'http://localhost:3000',
        'web.server.io': 'http://localhost:8080',
    },
    secure: false,
    ssl: {
        key: fs.readFileSync('../ssl/key.pem', 'utf8'),
        cert: fs.readFileSync('../ssl/cert.pem', 'utf8')
    }
})

server.on('upgrade', proxied.upgrade)

server.use('*', proxied)

server.listen(443)

The response has an issue with the SSL:

$ curl -k https://web.server.io -v
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to web.server.io (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
  CApath: none
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* error:1408F10B:SSL routines:ssl3_get_record:wrong version number
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
* Closing connection 0
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

The certificates have been generated with:

openssl req -x509 -nodes -days 730 -newkey rsa:4096 -keyout key.pem -out cert.pem -config san.config  -sha256

The san.config file:

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
C = IE
ST = My State
L = My City
O = MyCompany
OU = My Division
CN = web.server.io

[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = web.server.io
DNS.2 = api.server.io

averri avatar May 29 '19 18:05 averri

Please try this: https://github.com/antonymarion/node-http-proxy/blob/master/examples/http/proxy-https-to-https-chimurai.js

you were missing the express https server init.

https.createServer(httpsOpts, app) httpServer.listen(8010); // 8010 port in my test case

instead

const server = express() server.listen(443)

antonymarion avatar Aug 11 '21 15:08 antonymarion

Please try this: https://github.com/antonymarion/node-http-proxy/blob/master/examples/http/proxy-https-to-https-chimurai.js

you were missing the express https server init.

https.createServer(httpsOpts, app) httpServer.listen(8010); // 8010 port in my test case

instead

const server = express() server.listen(443)

It works for me

liubai678 avatar Apr 29 '22 06:04 liubai678

https://github.com/antonymarion/node-http-proxy/blob/master/examples/http/proxy-https-to-https-chimurai.js

This doesn't work for me, but you can pass your own https agent so I did that.

CezarManea avatar Dec 15 '22 09:12 CezarManea