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.


Alan
fonte
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).

nome de código-
fonte
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

Dere Sagar
fonte
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.

eomoto
fonte
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

Nishchit Dhanani
fonte
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: '[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);

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.

CoolAJ86
fonte
"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);
Shantanu Chandra
fonte
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 .

hoogw
fonte