Ativando HTTPS no express.js


408

Estou tentando fazer com que o HTTPS funcione no express.js para o nó, e não consigo descobrir.

Este é meu app.js código.

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);

Quando o executo, parece responder apenas a solicitações HTTP.

Eu escrevi baunilha simples node.js aplicativo HTTPS baseado em :

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);

E quando eu executo esse aplicativo, ele faz responder a solicitações HTTPS. Note que não acho que o toString () no resultado fs seja importante, pois usei combinações de ambos e ainda não es bueno.


EDITAR PARA ADICIONAR:

Para sistemas de produção, provavelmente é melhor usar o Nginx ou o HAProxy para fazer pedidos de proxy para o aplicativo nodejs. Você pode configurar o nginx para lidar com as solicitações de SSL e apenas falar http com o nó app.js.

EDITAR PARA ADICIONAR (6/6/2015)

Para sistemas em uso da AWS, é melhor usar o EC2 Elastic Load Balancers para lidar com a terminação SSL e permitir tráfego HTTP regular para seus servidores Web EC2. Para segurança adicional, configure seu grupo de segurança para que apenas o ELB possa enviar tráfego HTTP para as instâncias do EC2, o que impedirá que o tráfego HTTP não criptografado externo atinja suas máquinas.



3
Respondeu sucintamente aqui: stackoverflow.com/a/23894573/1882064
— arcseldon

Em relação ao último comentário da AWS: é necessário que um servidor não precise ser criado com o módulo https? Meus certificados são carregados na AWS via Jenkins e tratados com o ARN; Não tenho caminhos de arquivo para usar (em https opções)
— sqldoug

@sqldoug Não sei se entendi a pergunta. Os AWS ELBs podem ser configurados para aceitar conexões HTTPS e atuar como o ponto de terminação SSL. Ou seja, eles falam com seus servidores de aplicativos via HTTP comum. Normalmente, não há um motivo para os nodejs lidarem com SSL, porque é apenas uma sobrecarga de processamento extra que pode ser manipulada na pilha no nível ELB ou no nível do Proxy HTTP.
— 575 Alan Alan

Obrigado Alan; sim, desde então, percebi que o Node não precisa lidar com SSL quando os AWS ELBs podem ser configurados.
— Sqldoug

Respostas:


672

No express.js (desde a versão 3), você deve usar essa sintaxe:

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);

Dessa forma, você fornece middleware expresso para o servidor http / https nativo

Se você deseja que seu aplicativo seja executado em portas abaixo de 1024, será necessário usar o sudocomando (não recomendado) ou usar um proxy reverso (por exemplo, nginx, haproxy).


2
Tudo está escrito aqui: github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x Parágrafo Função de aplicativo
— codename-

74
Observe que, embora 443 seja a porta padrão para HTTPS, durante o desenvolvimento, você provavelmente deseja usar algo como 8443, porque a maioria dos sistemas não permite ouvintes não raiz em portas de número baixo.
— ebohlman

11
Homem, ele funciona como mágica :) Ele aceita .pem arquivos também, bem como deve de qualquer maneira
— Marcelo Teixeira Ruggeri

5
Express 4 Ela não funciona, ele funciona para localhost:80, mas nãohttps://localhost:443
— Muhammad Umer

13
se você estiver indo para usar nginx para proxy reverso, que pode lidar com os certificados SSL para você em vez de nó
— Gianfranco P.

48

Primeiro, você precisa criar selfsigned.key e selfsigned.crt arquivos. Vá para Criar um certificado SSL autoassinado ou siga as etapas a seguir.

Vá para o terminal e execute o seguinte comando.

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

  • Depois disso, coloque as seguintes informações
  • Nome do país (código de 2 letras) [AU]: US
  • Nome do estado ou província (nome completo) [Some-State]: NY
  • Nome da localidade (por exemplo, cidade) []: NY
  • Nome da organização (por exemplo, empresa) [Internet Widgits Pty Ltd]: xyz (Sua - Organização)
  • Nome da unidade organizacional (por exemplo, seção) []: xyz (nome da sua unidade)
  • Nome comum (por exemplo, servidor FQDN ou SEU nome) []: www.xyz.com (seu URL)
  • Endereço de email []: seu email

Após a criação, adiciona o arquivo key & cert no seu código e passa as opções para o servidor.

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)
});
  • Por fim, execute seu aplicativo usando https .

Mais informações https://github.com/sagardere/set-up-SSL-in-nodejs


O uso do sudo deve ser desencorajado, a menos que seja necessário. Acabei de passar por esse processo sem usar o sudo, mas estava logado como administrador na máquina.
— jhickok 2/01

27

Eu tive um problema semelhante ao fazer o SSL funcionar em uma porta diferente da porta 443. No meu caso, eu tinha um certificado de pacote configurável, além de um certificado e uma chave. O certificado do pacote configurável é um arquivo que contém vários certificados; o nó requer que você os quebre em elementos separados de uma matriz.

    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/")
    });

No app.js, você precisa especificar https e criar o servidor de acordo. Além disso, verifique se a porta que você está tentando usar está realmente permitindo o tráfego de entrada.


Eu tenho uma chave e um certificado em pacote, não sei o que cert: fs.readFileSync (PATH_TO_CERT) seria e como "quebrar" o certificado em pacote, existem mais de 20 chaves no certificado se você me perguntar :)
— Muhammad Umar

@MuhammadUmar, você não precisa quebrar o pacote ou até mesmo especificá-lo, se você não tiver um, você terá um certificado de pacote, se aplicável, e um certificado (chave pública) e chave (chave privada)
— Hayden Thring

@eomoto thanks bud! este é o melhor, você pregou totalmente o exemplo que eu precisava
— Hayden Thring

11

Incluindo pontos:

  1. Configuração SSL
    1. Em config / local.js
    2. Em config / env / production.js

Manipulação de HTTP e WS

  1. O aplicativo deve ser executado no HTTP em desenvolvimento para que possamos depurar facilmente o aplicativo.
  2. O aplicativo deve ser executado em HTTPS em produção por questões de segurança.
  3. A solicitação HTTP de produção de aplicativos sempre deve ser redirecionada para https.

Configuração SSL

No Sailsjs, existem duas maneiras de configurar todo o material, primeiro é o de configurar na pasta de configuração, cada um com seus arquivos separados (como a conexão com o banco de dados referente às configurações encontra-se em connections.js). E o segundo é configurar na estrutura de arquivos base do ambiente, cada arquivo de ambiente é apresentado emconfig/env pasta e cada arquivo contém configurações para um ambiente específico.

O Sails primeiro procura na pasta config / env e depois espera config / * .js

Agora vamos configurar o 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;

Alternativa, você pode adicionar isso em config / env / production.js também. (Este trecho também mostra como lidar com vários certificados CARoot)

Ou em 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')
    }
};

redirecionamento http / https e ws / wss

Aqui ws é Web Socket e o wss representa o Secure Web Socket, conforme configuramos o ssl e agora http e ws os dois pedidos se tornam seguros e se transformam em https e wss, respectivamente.

Existem muitas fontes em nosso aplicativo que receberão solicitação como qualquer postagem de blog, mídia social, mas nosso servidor é executado apenas em https, portanto, quando qualquer solicitação vem de http, é exibido o erro "Este site não pode ser alcançado" no navegador do cliente. E perdemos o tráfego do nosso site. Portanto, devemos redirecionar a solicitação http para https, as mesmas regras permitem o websocket, caso contrário, o socket falhará.

Portanto, precisamos executar o mesmo servidor na porta 80 (http) e desviar todas as solicitações para a porta 443 (https). Navega primeiro compile o arquivo config / bootstrap.js antes de levantar o servidor. Aqui podemos iniciar nosso servidor expresso na porta 80.

Em config / bootstrap.js (crie um servidor http e redirecione todas as solicitações para 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();
};

Agora você pode visitar http://www.seudominio.com , ele será redirecionado para https://www.seudominio.com


8

Use greenlock-express: SSL grátis, HTTPS automatizado

Greenlock lida com emissão e renovação de certificado (via Let's Encrypt) e redirecionamento http => https, para uso.

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);

Screencast

Assista à demonstração do QuickStart: https://youtu.be/e8vaR4CEZ5s

Para Localhost

Basta responder a essa questão com antecedência porque é uma pergunta comum de acompanhamento:

Você não pode ter certificados SSL no host local. No entanto, você pode usar algo como o Telebit, que permitirá executar aplicativos locais como reais.

Você também pode usar domínios privados com o Greenlock via desafios do DNS-01, mencionados no README, juntamente com vários plugins que o suportam.

Portas não padrão (ou seja, não 80/443)

Leia a nota acima sobre o host local - você também não pode usar portas não padrão com o Let's Encrypt.

No entanto, você pode expor suas portas internas não padrão como portas padrão externas via encaminhamento de porta, rota sni ou usar algo como Telebit que faz roteamento SNI e encaminhamento / retransmissão de porta para você.

Você também pode usar os desafios do DNS-01, caso em que não precisará expor portas e também pode proteger domínios em redes privadas dessa maneira.


"Você não pode ter certificados SSL no host local." - Tenho o SSL funcionando no meu aplicativo React no host local. Vi aqui procurando como fazê-lo funcionar no Express. React é meu front-end e Express é meu back-end. Preciso que ele funcione para o Stripe, pois minha postagem no Stripe deve estar em SSL. Deve ser óbvio, mas no localhost eu estou testando e no servidor será produção.
— Taersious

Correção: "Você não pode ter certificados SSL válidos no host local".
— CoolAJ86

6

É assim que está funcionando para mim. O redirecionamento usado também redirecionará todos os http normais.

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

Este é o meu código de trabalho para o Express 4.0 .

O Express 4.0 é muito diferente do 3.0 e de outros.

4.0 você tem o arquivo / bin / www, que você adicionará https aqui.

"npm start" é a maneira padrão de iniciar o servidor express 4.0.

A função readFileSync () deve usar __dirname get directory atual

Enquanto require () use ./, consulte o diretório atual.

Primeiro, você coloca o arquivo private.key e public.cert na pasta / bin. É a mesma pasta do arquivo WWW .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.