我一直在尝试用我正在做的一个node.js项目来设置HTTPS。我基本上遵循了这个例子的node.js文档:
// curl -k https://localhost:8000/
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
现在,当我做的时候
curl -k https://localhost:8000/
我得到
hello world
像预期的那样。但如果我这样做了
curl -k http://localhost:8000/
我得到
curl: (52) Empty reply from server
回想起来,这似乎是显而易见的,它将以这种方式工作,但与此同时,最终访问我的项目的人不会输入https://yadayada,我希望所有的流量从他们访问网站的那一刻起就使用https。
我怎么能得到节点(和Express,因为这是我正在使用的框架)把所有传入的流量交给https,不管它是否被指定?我还没有找到任何解决这个问题的文档。或者只是假设在生产环境中,节点在它前面有一些东西(例如nginx)来处理这种重定向?
这是我第一次尝试web开发,所以如果这是显而易见的,请原谅我的无知。
莱恩,谢谢你给我指明了方向。我用一些代码充实了你的答案(第二段),它是有效的。在这个场景中,这些代码片段被放在我的express应用程序中:
// set up plain http server
var http = express();
// set up a route to redirect http to https
http.get('*', function(req, res) {
res.redirect('https://' + req.headers.host + req.url);
// Or, if you don't want to automatically detect the domain name from the request header, you can hard code it:
// res.redirect('https://example.com' + req.url);
})
// have it listen on 8080
http.listen(8080);
https express服务器监听3000上的ATM。我设置了这些iptables规则,这样节点就不必以root用户运行:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 3000
总的来说,这和我想要的完全一样。
为了防止通过HTTP窃取cookie,请参阅以下答案(来自评论)或使用以下代码:
const session = require('cookie-session');
app.use(
session({
secret: "some secret",
httpOnly: true, // Don't let browser javascript access cookies.
secure: true, // Only use cookies over https.
})
);
这个答案需要更新以与Express 4.0一起工作。下面是我如何让单独的http服务器工作:
var express = require('express');
var http = require('http');
var https = require('https');
// Primary https app
var app = express()
var port = process.env.PORT || 3000;
app.set('env', 'development');
app.set('port', port);
var router = express.Router();
app.use('/', router);
// ... other routes here
var certOpts = {
key: '/path/to/key.pem',
cert: '/path/to/cert.pem'
};
var server = https.createServer(certOpts, app);
server.listen(port, function(){
console.log('Express server listening to port '+port);
});
// Secondary http app
var httpApp = express();
var httpRouter = express.Router();
httpApp.use('*', httpRouter);
httpRouter.get('*', function(req, res){
var host = req.get('Host');
// replace the port in the host
host = host.replace(/:\d+$/, ":"+app.get('port'));
// determine the redirect destination
var destination = ['https://', host, req.url].join('');
return res.redirect(destination);
});
var httpServer = http.createServer(httpApp);
httpServer.listen(8080);
如果你遵循传统端口,因为HTTP默认尝试端口80,HTTPS默认尝试端口443,你可以简单地在同一台机器上有两个服务器:
代码如下:
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem')
};
https.createServer(options, function (req, res) {
res.end('secure!');
}).listen(443);
// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
使用https测试:
$ curl https://127.0.0.1 -k
secure!
与http:
$ curl http://127.0.0.1 -i
HTTP/1.1 301 Moved Permanently
Location: https://127.0.0.1/
Date: Sun, 01 Jun 2014 06:15:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked
更多细节:Nodejs HTTP和HTTPS通过相同的端口
我使用Basarat提出的解决方案,但我还需要覆盖端口,因为我曾经有2个不同的端口用于HTTP和HTTPS协议。
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
我也喜欢使用非标准端口,这样就可以在没有root权限的情况下启动nodejs。
我喜欢8080和8443,因为我在tomcat上编程了很多年。
我的完整文件变成
var fs = require('fs');
var http = require('http');
var http_port = process.env.PORT || 8080;
var app = require('express')();
// HTTPS definitions
var https = require('https');
var https_port = process.env.PORT_HTTPS || 8443;
var options = {
key : fs.readFileSync('server.key'),
cert : fs.readFileSync('server.crt')
};
app.get('/', function (req, res) {
res.send('Hello World!');
});
https.createServer(options, app).listen(https_port, function () {
console.log('Magic happens on port ' + https_port);
});
// Redirect from http port to https
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
console.log("http request, will go to >> ");
console.log("https://" + req.headers['host'].replace(http_port,https_port) + req.url );
res.end();
}).listen(http_port);
然后我使用iptable在我的HTTP和HTTPS端口上forword80和443流量。
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8443
这招对我很管用:
/* Headers */
require('./security/Headers/HeadersOptions').Headers(app);
/* Server */
const ssl = {
key: fs.readFileSync('security/ssl/cert.key'),
cert: fs.readFileSync('security/ssl/cert.pem')
};
//https server
https.createServer(ssl, app).listen(443, '192.168.1.2' && 443, '127.0.0.1');
//http server
app.listen(80, '192.168.1.2' && 80, '127.0.0.1');
app.use(function(req, res, next) {
if(req.secure){
next();
}else{
res.redirect('https://' + req.headers.host + req.url);
}
});
建议在重定向到https之前添加头
现在,当你这样做时:
curl http://127.0.0.1 --include
你会得到:
HTTP/1.1 302 Found
//
Location: https://127.0.0.1/
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 40
Date: Thu, 04 Jul 2019 09:57:34 GMT
Connection: keep-alive
Found. Redirecting to https://127.0.0.1/
我使用快捷4.17.1
经过多年研究从http到https的完美重定向,我在这里找到了完美的解决方案。
const http = require("http");
const https = require("https");
const { parse } = require("url");
const next = require("next");
const fs = require("fs");
const ports = {
http: 3000,
https: 3001
}
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const httpsOptions = {
key: fs.readFileSync("resources/certificates/localhost-key.pem"),
cert: fs.readFileSync("resources/certificates/localhost.pem")
};
// Automatic HTTPS connection/redirect with node.js/express
// source: https://stackoverflow.com/questions/7450940/automatic-https-
connection-redirect-with-node-js-express
app.prepare().then(() => {
// Redirect from http port to https
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(ports.http, ports.https) + req.url });
console.log("http request, will go to >> ");
console.log("https://" + req.headers['host'].replace(ports.http, ports.https) + req.url);
res.end();
}).listen(ports.http, (err) => {
if (err) throw err;
console.log("ready - started server on url: http://localhost:" + ports.http);
});
https.createServer(httpsOptions, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
}).listen(ports.https, (err) => {
if (err) throw err;
console.log("ready - started server on url: https://localhost:" + ports.https);
});
});