作業中の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)がノードの前にあると想定されていますか?
これはウェブ開発への私の最初の進出です。もしこれが明白なものであるならば、私の無知を許してください。
ライアン、私を正しい方向に向けてくれてありがとう。私はあなたの答え(第2段落)をいくつかのコードで少し具体化しましたが、それはうまくいきます。このシナリオでは、これらのコードスニペットがエクスプレスアプリに配置されます。
// set up plain http server
var http = express.createServer();
// 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エクスプレスサーバーは3000でATMをリッスンします。ノードをルートとして実行する必要がないように、これらのiptablesルールを設定しました。
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がデフォルトでポート80を試行し、HTTPSがデフォルトでポート443を試行するため、従来のポートに従う場合、同じマシン上に2台のサーバーを配置できます。コードは次のとおりです。
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
この男に感謝: https://www.tonyerwin.com/2014/09/redirecting-http-to-https-with-nodejs.html
app.use (function (req, res, next) {
if (req.secure) {
// request was via https, so do no special handling
next();
} else {
// request was via http, so redirect to https
res.redirect('https://' + req.headers.Host + req.url);
}
});
Nginxを使用すると、「x-forwarded-proto」ヘッダーを利用できます。
function ensureSec(req, res, next){
if (req.headers["x-forwarded-proto"] === "https"){
return next();
}
res.redirect("https://" + req.headers.Host + req.url);
}
0.4.12の時点では、NodeのHTTP/HTTPSサーバーを使用して同じポートでHTTPとHTTPSをリッスンする実際のクリーンな方法はありません。
NodeのHTTPSサーバー(これはExpress.jsでも動作します)が443(または他のポート)をリッスンし、小さなHTTPサーバーが80にバインドし、ユーザーを安全なポートにリダイレクトさせることで、この問題を解決した人もいます。
単一のポートで両方のプロトコルを絶対に処理できるようにする必要がある場合は、nginx、lighttpd、Apache、またはその他のWebサーバーをそのポートに配置し、Nodeのリバースプロキシとして機能する必要があります。
この回答は、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);
私は、エクスプレスを使用しているときにreq.protocolが動作することを発見しました(なしではテストしていませんが、動作すると思われます)。 Express 3.4.3で現在のノード0.10.22を使用
app.use(function(req,res,next) {
if (!/https/.test(req.protocol)){
res.redirect("https://" + req.headers.Host + req.url);
} else {
return next();
}
});
アプリが信頼できるプロキシ(AWS ELBまたは正しく設定されたnginxなど)の背後にある場合、このコードは機能するはずです:
app.enable('trust proxy');
app.use(function(req, res, next) {
if (req.secure){
return next();
}
res.redirect("https://" + req.headers.Host + req.url);
});
ノート:
ここでのほとんどの回答は、req.headers.Hostヘッダーを使用することを示唆しています。
HostヘッダーはHTTP 1.1で必要ですが、ヘッダーは実際にはHTTPクライアントによって送信されない場合があり、node/expressはこのリクエストを受け入れるため、実際にはオプションです。
あなたは尋ねるかもしれません:どのHTTPクライアント(例:ブラウザー)がそのヘッダーのないリクエストを送信できますか? HTTPプロトコルは非常に簡単です。 Hostヘッダーを送信しないように、数行のコードでHTTPリクエストを作成できます。不正なリクエストを受信するたびに例外をスローすると、そのような例外の処理方法によっては、サーバーがダウンする可能性があります。
常にすべての入力を検証する。これは妄想ではありません。サービスにHostヘッダーのないリクエストを受け取りました。
また、RLを文字列として扱わないでください。ノードURLモジュールを使用して、文字列の特定の部分を変更します。 URLを文字列として扱うことは、多くのさまざまな方法で活用できます。しないでください。
express-force-https モジュールを使用できます:
npm install --save express-force-https
var express = require('express');
var secure = require('express-force-https');
var app = express();
app.use(secure);
var express = require('express');
var app = express();
app.get('*',function (req, res) {
res.redirect('https://<domain>' + req.url);
});
app.listen(80);
これが私たちが使用しているものであり、うまく機能します!
「net」モジュールを使用して、同じポートでHTTPとHTTPSをリッスンできます。
var https = require('https');
var http = require('http');
var fs = require('fs');
var net=require('net');
var handle=net.createServer().listen(8000)
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(handle);
http.createServer(function(req,res){
res.writeHead(200);
res.end("hello world\n");
}).listen(handle)
Basaratが提案したソリューションを使用しますが、HTTPおよびHTTPSプロトコル用に2つの異なるポートを使用していたため、ポートを上書きする必要もあります。
res.writeHead(301, { "Location": "https://" + req.headers['Host'].replace(http_port,https_port) + req.url });
また、ルート権限なしで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);
次に、HTTPおよびHTTPSポートで80および443トラフィックを予測するためにiptableを使用します。
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
これは私のために働いた:
app.use(function(req,res,next) {
if(req.headers["x-forwarded-proto"] == "http") {
res.redirect("https://[your url goes here]" + req.url, next);
} else {
return next();
}
});
2つのNode.jsサーバーをインスタンス化できます-HTTPとHTTPS用に1つ
両方のサーバーが実行するセットアップ関数を定義することもできます。そのため、多くの重複コードを記述する必要はありません。
私がやった方法は次のとおりです(restify.jsを使用しますが、express.jsまたはノード自体でも動作するはずです)
http://qugstart.com/blog/node-js/node-js-restify-server-with-both-http-and-https/
これは私のために働いた:
/* 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/
Express 4.17.1を使用します