关于node.js:在express.js上启用HTTPS

Enabling HTTPS on express.js

我正在尝试让HTTPS在express.js上运行节点,我无法弄明白。

这是我的app.js代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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请求。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
');
});

server.listen(8000);

当我运行这个应用程序时,它会响应HTTPS请求。请注意,我不认为fs上的toString()结果很重要,因为我已经使用了两者的组合而仍然没有es bueno。

编辑添加:

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

编辑添加(4/6/2015)

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


在express.js中(从版本3开始),您应该使用该语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    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并相应地创建服务器。此外,请确保您尝试使用的端口实际上允许入站流量。


首先,您需要创建selfsigned.key和selfsigned.crt文件。
转到创建自签名SSL证书

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

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

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

After creation adds key & cert file in your code, and pass the options to the server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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运行您的应用程序。

More information https://github.com/sagardere/set-up-SSL-in-nodejs


包括点数:

  • SSL设置

  • 在config / local.js中
  • 在config / env / production.js中
  • HTTP和WS处理

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

    在Sailsjs中,有两种方法可以配置所有的东西,首先是在config文件夹中配置,每个都有自己独立的文件(比如关于设置的数据库连接位于connections.js中)。第二个是在环境基础文件结构上配置,每个环境文件都存在于config/env文件夹中,每个文件包含特定环境的设置。

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

    现在让我们在config/local.js中设置ssl。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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;

    Alternative you can add this in config/env/production.js too. (This snippet also show how to handle multiple CARoot certi)

    或者在production.js中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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重定向

    这里是Web Socket和wss代表Secure Web Socket,因为我们现在设置ssl http和ws两个请求变得安全并分别转换为https和wss。

    我们的应用程序有很多来源会收到任何博客文章,社交媒体发布的请求,但我们的服务器只在https上运行所以当任何来自http的请求它在客户端浏览器中给出"此站点无法访问"错误。我们失去了网站流量。所以我们必须将http请求重定向到https,同样的规则允许websocket,否则socket将失败。

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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();
    };

    Now you can visit http://www.yourdomain.com, it will redirect to https://www.yourdomain.com


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

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

    express-app.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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: '[email protected]'
    , 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

    >
</p>
<p>对于Localhost</p>
<p>
只是提前回答这个问题,因为这是一个常见的后续问题:
</p>
<p>
您无法在localhost上拥有SSL证书。但是,您可以使用像Telebit这样的东西,它允许您将本地应用程序作为真实应用程序运行。
</p>
<p>
您还可以通过DNS-01挑战使用Greenlock的私有域,这在README中提到,以及支持它的各种插件。
</p>
<p>非标准端口(即没有80/443)</p>
<p>
阅读上面关于localhost的说明 - 您也不能使用Let's Encrypt的非标准端口。
</p>
<p>
但是,您可以通过端口转发,sni-route将内部非标准端口公开为外部标准端口,或者使用Telebit为您执行SNI路由和端口转发/中继。
</p>
<p>
您也可以使用DNS-01挑战,在这种情况下,您根本不需要公开端口,也可以通过这种方式保护专用网络上的域。
</p>
<hr>
<p>
这就是它为我工作的方式。使用的重定向也将重定向所有正常的http。
</p>
<div class=

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    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);


    这是我为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文件是同一个文件夹。