在express.js上启用HTTPS


408

我正在尝试让HTTPS在node.express.js上工作,但我无法弄清楚。

这是我的app.js代码。

var express = require('express');
var fs = require('fs');

var privateKey = fs.readFileSync('sslcert/server.key');
var certificate = fs.readFileSync('sslcert/server.crt');

var credentials = {key: privateKey, cert: certificate};


var app = express.createServer(credentials);

app.get('/', function(req,res) {
    res.send('hello');
});

app.listen(8000);

当我运行它时,它似乎仅响应HTTP请求。

我写了简单的node.js基于香草的HTTPS应用程序:

var   fs = require("fs"),
      http = require("https");

var privateKey = fs.readFileSync('sslcert/server.key').toString();
var certificate = fs.readFileSync('sslcert/server.crt').toString();

var credentials = {key: privateKey, cert: certificate};

var server = http.createServer(credentials,function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
});

server.listen(8000);

当我运行此应用程序时,它确实响应HTTPS请求。请注意,我认为fs结果上的toString()并不重要,因为我使用了两者的组合,但仍然没有es bueno。


编辑添加:

对于生产系统,最好使用Nginx或HAProxy将请求代理到您的nodejs应用。您可以设置nginx来处理ssl请求,而只对您的节点app.js说HTTP。

编辑添加(4/6/2015)

对于使用AWS的系统,最好使用EC2 Elastic Load Balancer来处理SSL终止,并允许将常规HTTP流量发送到EC2 Web服务器。为了进一步提高安全性,请设置安全组,以便仅允许ELB将HTTP流量发送到EC2实例,这将防止外部未加密的HTTP流量攻击您的计算机。




关于AWS的最新评论:是否不需要使用https模块创建服务器?我的证书通过Jenkins上传到AWS并由ARN处理;我没有要使用的文件路径(在https选项中)
sqldoug

@sqldoug我不确定我是否理解这个问题。可以将AWS ELB配置为接受HTTPS连接并充当SSL终止点。也就是说,它们通过常规HTTP与您的应用服务器对话。通常没有理由让nodejs处理SSL,因为这只是额外的处理开销,可以在ELB级别或HTTP代理级别上在堆栈中处理。
艾伦(Alan)

谢谢艾伦;是的,自那以后,我意识到当可以配置AWS ELB时,Node无需处理SSL。
sqldoug '16

Answers:


671

在express.js(版本3起)中,应使用以下语法:

var fs = require('fs');
var http = require('http');
var https = require('https');
var privateKey  = fs.readFileSync('sslcert/server.key', 'utf8');
var certificate = fs.readFileSync('sslcert/server.crt', 'utf8');

var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var app = express();

// your express configuration here

var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);

httpServer.listen(8080);
httpsServer.listen(8443);

这样,您就可以向本地http / https服务器提供快速中间件

如果您希望应用程序在1024以下的端口上运行,则需要使用sudo命令(不建议使用)或使用反向代理(例如nginx,haproxy)。


2
所有内容都写在这里:github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x段落应用程序功能
代号

74
请注意,尽管443是HTTPS的默认端口,但是在开发过程中您可能想要使用类似8443的名称,因为大多数系统不允许在低编号端口上使用非root用户侦听器。
ebohlman

1
天哪,它的工作原理就像魔术:)它也接受.pem文件,无论如何也应接受
Marcelo Teixeira Ruggeri 2014年

5
表达4它不起作用,它适用localhost:80但不起作用https://localhost:443
Muhammad Umer

13
如果您打算使用nginx进行反向代理,则可以为您而不是节点处理ssl证书
Gianfranco P.

48

首先,您需要创建selfsigned.keyselfsigned.crt文件。转到创建自签名SSL证书,或执行以下步骤。

转到终端并运行以下命令。

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./selfsigned.key -out selfsigned.crt

  • 之后,输入以下信息
  • 国家名称(2个字母代码)[AU]:美国
  • 州或省名称(全名)[某些州]:NY
  • 地点名称(例如城市)[]:纽约
  • 组织名称(例如公司)[Internet Widgits Pty Ltd]:xyz(您的组织)
  • 组织单位名称(例如,部分)[]:xyz(您的单位名称)
  • 通用名称(例如服务器FQDN或您的姓名)[]:www.xyz.com(您的URL)
  • 电子邮件地址[]:您的电子邮件

创建后,在您的代码中添加密钥和证书文件,并将选项传递给服务器。

const express = require('express');
const https = require('https');
const fs = require('fs');
const port = 3000;

var key = fs.readFileSync(__dirname + '/../certs/selfsigned.key');
var cert = fs.readFileSync(__dirname + '/../certs/selfsigned.crt');
var options = {
  key: key,
  cert: cert
};

app = express()
app.get('/', (req, res) => {
   res.send('Now using https..');
});

var server = https.createServer(options, app);

server.listen(port, () => {
  console.log("server starting on port : " + port)
});
  • 最后使用https运行您的应用程序。

更多信息https://github.com/sagardere/set-up-SSL-in-nodejs


除非必要,否则不建议使用sudo。我只是在不使用sudo的情况下完成了此过程,但是我以admin的身份登录了计算机。
jhickok

27

使SSL在端口443以外的其他端口上运行时,我遇到了类似的问题。在我的情况下,我有捆绑包证书以及证书和密钥。捆绑包证书是一个包含多个证书的文件,节点要求您将这些证书分成数组的单独元素。

    var express = require('express');
    var https = require('https');
    var fs = require('fs');

    var options = {
      ca: [fs.readFileSync(PATH_TO_BUNDLE_CERT_1), fs.readFileSync(PATH_TO_BUNDLE_CERT_2)],
      cert: fs.readFileSync(PATH_TO_CERT),
      key: fs.readFileSync(PATH_TO_KEY)
    };

    app = express()

    app.get('/', function(req,res) {
        res.send('hello');
    });

    var server = https.createServer(options, app);

    server.listen(8001, function(){
        console.log("server running at https://IP_ADDRESS:8001/")
    });

在app.js中,您需要指定https并相应地创建服务器。另外,请确保您尝试使用的端口实际上允许入站流量。


我有一个密钥和一个捆绑的证书,我不确定是什么证书:fs.readFileSync(PATH_TO_CERT),以及如何“破坏”捆绑的证书,如果您问我,证书中有20多个密钥:)
Muhammad Umar

@MuhammadUmar,您不必破坏捆绑包,甚至无需指定捆绑包,也可以指定捆绑包证书(如果适用)以及cert(公钥)和密钥(私钥)
Hayden Thring,

@eomoto谢谢芽!这是最好的,您完全确定了我需要的示例
Hayden Thring

11

包括积分:

  1. SSL设置
    1. 在config / local.js中
    2. 在config / env / production.js中

HTTP和WS处理

  1. 该应用程序必须在开发中的HTTP上运行,以便我们可以轻松调试我们的应用程序。
  2. 出于安全考虑,该应用必须在生产环境中的HTTPS上运行。
  3. 应用程序生产HTTP请求应始终重定向到https。

SSL配置

在Sailsjs中,有两种方法可以配置所有内容,第一种是在config文件夹中进行配置,每个文件夹都有各自的文件(例如,有关设置的数据库连接位于connections.js中)。其次是在环境基础文件结构上进行配置,每个环境文件都存在于config/env文件夹中,并且每个文件都包含特定环境的设置。

Sails首先查看config / env文件夹,然后期待config / * .js

现在,在中设置ssl config/local.js

var local = {
   port: process.env.PORT || 1337,
   environment: process.env.NODE_ENV || 'development'
};

if (process.env.NODE_ENV == 'production') {
    local.ssl = {
        secureProtocol: 'SSLv23_method',
        secureOptions: require('constants').SSL_OP_NO_SSLv3,
        ca: require('fs').readFileSync(__dirname + '/path/to/ca.crt','ascii'),
        key: require('fs').readFileSync(__dirname + '/path/to/jsbot.key','ascii'),
        cert: require('fs').readFileSync(__dirname + '/path/to/jsbot.crt','ascii')
    };
    local.port = 443; // This port should be different than your default port
}

module.exports = local;

或者,您也可以在config / env / production.js中添加它。(此代码段还显示了如何处理多个CARoot证书)

或在production.js中

module.exports = {
    port: 443,
    ssl: {
        secureProtocol: 'SSLv23_method',
        secureOptions: require('constants').SSL_OP_NO_SSLv3,
        ca: [
            require('fs').readFileSync(__dirname + '/path/to/AddTrustExternalCARoot.crt', 'ascii'),
            require('fs').readFileSync(__dirname + '/path/to/COMODORSAAddTrustCA.crt', 'ascii'),
            require('fs').readFileSync(__dirname + '/path/to/COMODORSADomainValidationSecureServerCA.crt', 'ascii')
        ],
        key: require('fs').readFileSync(__dirname + '/path/to/jsbot.key', 'ascii'),
        cert: require('fs').readFileSync(__dirname + '/path/to/jsbot.crt', 'ascii')
    }
};

http / https和ws / wss重定向

这里的ws是Web套接字,而wss表示安全Web套接字,当我们设置ssl时,现在http和ws这两个请求都变得安全并分别转换为https和wss。

我们的应用程序有许多来源会像其他博客文章,社交媒体文章一样接收请求,但是我们的服务器仅在https上运行,因此当任何来自http的请求时,它会在客户端浏览器中显示“无法访问此网站”错误。而且我们损失了我们的网站流量。因此,我们必须将http请求重定向到https,相同的规则允许使用websocket,否则套接字将失败。

因此,我们需要在端口80(http)上运行同一服务器,并将所有请求转移到端口443(https)。在提升服务器之前,首先运行config / bootstrap.js文件。在这里,我们可以在端口80上启动快速服务器。

在config / bootstrap.js中(创建http服务器并将所有请求重定向到https)

module.exports.bootstrap = function(cb) {
    var express = require("express"),
        app = express();

    app.get('*', function(req, res) {  
        if (req.isSocket) 
            return res.redirect('wss://' + req.headers.host + req.url)  

        return res.redirect('https://' + req.headers.host + req.url)  
    }).listen(80);
    cb();
};

现在,您可以访问http://www.yourdomain.com,它将重定向到https://www.yourdomain.com


8

使用greenlock-express:免费SSL,自动HTTPS

Greenlock开箱即用地处理证书的发行和续签(通过Let's Encrypt)和http => https重定向。

express-app.js

var express = require('express');
var app = express();

app.use('/', function (req, res) {
  res.send({ msg: "Hello, Encrypted World!" })
});

// DO NOT DO app.listen()
// Instead export your app:
module.exports = app;

server.js

require('greenlock-express').create({
  // Let's Encrypt v2 is ACME draft 11
  version: 'draft-11'
, server: 'https://acme-v02.api.letsencrypt.org/directory'

  // You MUST change these to valid email and domains
, email: 'john.doe@example.com'
, approveDomains: [ 'example.com', 'www.example.com' ]
, agreeTos: true
, configDir: "/path/to/project/acme/"

, app: require('./express-app.j')

, communityMember: true // Get notified of important updates
, telemetry: true       // Contribute telemetry data to the project
}).listen(80, 443);

截屏

观看QuickStart演示:https : //youtu.be/e8vaR4CEZ5s

对于本地主机

只是提前回答这个问题,因为这是一个常见的后续问题:

您不能在本地主机上拥有SSL证书。但是,您可以使用Telebit之类的工具,使您可以将本地应用程序作为真实应用程序运行。

您还可以通过DNS-01挑战将私有域与Greenlock一起使用,这在README中已提及,并提供了支持它的各种插件。

非标准端口(即80/443)

阅读以上有关localhost的注释-您也不能通过Let's Encrypt使用非标准端口。

但是,您可以通过端口转发,sni-route将内部非标准端口公开为外部标准端口,或者使用Telebit之类的东西为您执行SNI路由和端口转发/中继。

您还可以使用DNS-01挑战,在这种情况下,您根本不需要公开端口,也可以通过这种方式保护私有网络上的域。


“您不能在本地主机上拥有SSL证书。” -我在本地主机上的React应用上使用SSL。来到这里寻找如何使其在Express中工作。React是我的前端,Express是我的后端。需要它用于Stripe,因为我在Stripe上的帖子必须使用SSL。应该很明显,但是我正在localhost中进行测试,并且将在服务器上进行生产。
Taersious

更正:“您在本地主机上不能具有有效的 SSL证书”。
CoolAJ86 '19

6

这就是它为我工作的方式。使用的重定向也将重定向所有正常的http。

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
var request = require('request');
//For https
const https = require('https');
var fs = require('fs');
var options = {
  key: fs.readFileSync('certificates/private.key'),
  cert: fs.readFileSync('certificates/certificate.crt'),
  ca: fs.readFileSync('certificates/ca_bundle.crt')
};

// API file for interacting with MongoDB
const api = require('./server/routes/api');

// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Angular DIST output folder
app.use(express.static(path.join(__dirname, 'dist')));

// API location
app.use('/api', api);

// Send all other requests to the Angular app
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'));
});
app.use(function(req,resp,next){
  if (req.headers['x-forwarded-proto'] == 'http') {
      return resp.redirect(301, 'https://' + req.headers.host + '/');
  } else {
      return next();
  }
});


http.createServer(app).listen(80)
https.createServer(options, app).listen(443);

0

这是我的Express 4.0的工作代码

express 4.0与3.0和其他版本有很大的不同。

4.0中有/ bin / www文件,您将在此处添加https。

“ npm start”是启动Express 4.0服务器的标准方法。

readFileSync()函数应使用__dirname获取当前目录

而require()使用./引用当前目录。

首先,将private.key和public.cert文件放在/ bin文件夹下,它与WWW文件位于同一文件夹

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.