2012-08-31 36 views
23

Quiero devolver dinámicamente una información de certificado ssl en mi aplicación NodeJS. Tengo dos nombres de dominio vinculados a la misma aplicación de nodo. Solo veo que las configuraciones de SSL se pueden especificar cuando se crea el servidor. ¿Es posible devolver dinámicamente certificados SSL basados ​​en la URL solicitada?¿Es posible devolver dinámicamente un certificado SSL en NodeJS?

De lo contrario, si en su lugar debo crear una segunda instancia de servidor en otro puerto, ¿podré canalizar cada solicitud de forma transparente al puerto original? ¿Puedo hacer que parezca que no se está ejecutando en un segundo puerto?

Gracias, Jeff

+1

Me gustaría una respuesta a esto también. Estoy planeando crear una aplicación Node.js que pueda alojar varios dominios con un certificado SSL para cada uno. Sería útil si podemos almacenar la información del certificado SSL en la base de datos. Entonces, una vez que detectamos el dominio del que provienen, podemos servir el contenido y el tema de su sitio. Sé que Node.js tiene una forma de definir un certificado SSL para cuando se inicia, pero no se sabe de una forma de hacerlo de forma dinámica en función del dominio en el que se encuentran. – Keverw

+1

no estoy seguro, pero ¿no sería útil https://github.com/nodejitsu/node-http-proxy? –

Respuesta

41

Sí, es posible hacerlo con un servidor. Pero la advertencia es que funciona en clientes que admiten SNI, que es la mayoría de los navegadores modernos.

Así es como se hace:

//function to pick out the key + certs dynamically based on the domain name 
function getSecureContext (domain) { 
    return crypto.createCredentials({ 
     key: fs.readFileSync('/path/to/domain.key'), 
     cert: fs.readFileSync('/path/to/domain.crt'), 
     ca: [fs.readFileSync('/path/to/CA_cert_1.crt'), fs.readFileSync('/path/to/CA_cert_2.crt'), <include all CA certs that you have to> ... ] 
     }).context; 
} 

//read them into memory 
var secureContext = { 
    'domain1': getSecureContext('domain1'), 
    'domain2': getSecureContext('domain2'), 
    . 
    . 
} 

//provide a SNICallback when you create the options for the https server 
var options = { 
    SNICallback: function (domain) { 
     return secureContext[domain]; 
    }, //SNICallback is passed the domain name, see NodeJS docs on TLS 
    cert: fs.readFileSync('/path/to/server.crt'), 
    key: fs.readFileSync('/path/to/server.key'),     
    } 
} 

//create your https server 
var server = require('https').createServer(options, [requestListener]); 
//using Express 
var server = require('https').createServer(options, require('express')()); 
server.listen(<someport>); 

Esto funciona porque the options for https es similar a tls.createServer(). Asegúrese de incluir todos los certificados intermedios y raíz de CA necesarios en la llamada crypto.createCredentials. Además, si tiene un paquete de CA, divídalos en varios archivos de crt individuales antes de usarlos, ya que 'ca' acepta una matriz de certificados.

+0

¡Agradable! ¿Cada certificado SSL necesitará tener una IP dedicada? Quiero alojar múltiples dominios con SSL en el mismo servidor. Calculados cuando compran su sitio, automáticamente compraremos un certificado SSL y un dominio para ellos utilizando una API. Si pudiera ejecutar varios dominios en el mismo servidor con la misma IP, sería genial, pero tengo la sensación de que cada cert necesitará una IP dedicada pero no muy segura. – Keverw

+0

y me gustaría estar disponible para eliminar/agregar sitios web dinámicamente. Construir una aplicación SaaS o, al menos, querer, y esta parte sería algo que tenemos que resolver temprano. Después de leer esa página de wikipedia, parece que no necesitamos una IP dedicada. Así que eso es una ventaja, pero ¿getSecureContext se llama a la hora de solicitud o cuando el servidor se inicia? Porque getSecureContext podría buscar en una base de datos cada vez que el sitio recibe una solicitud para el certificado SSL. hmm.Tratando de pensar sobre cómo debería funcionar esto. – Keverw

+0

y me pregunto qué hará en los navegadores más antiguos que no lo admiten. Darles errores de certificado, supongo? – Keverw

15

crypto.createCredentials() está en desuso, por lo tanto, use tls.createSecureContext().

tls.createServer() deben tener key y cert en las opciones, porque se requieren en el manual. Tal vez tls.createServer() utiliza estos parámetros como valores predeterminados en el caso SNICallback no es compatible.

var secureContext = { 
    'mydomain.com': tls.createSecureContext({ 
     key: fs.readFileSync('../path_to_key1.pem', 'utf8'), 
     cert: fs.readFileSync('../path_to_cert1.crt', 'utf8'), 
     ca: fs.readFileSync('../path_to_certificate_authority_bundle.ca-bundle1', 'utf8'), // this ca property is optional 
    }), 
    'myotherdomain.com': tls.createSecureContext({ 
     key: fs.readFileSync('../path_to_key2.pem', 'utf8'), 
     cert: fs.readFileSync('../path_to_cert2.crt', 'utf8'), 
     ca: fs.readFileSync('../path_to_certificate_authority_bundle.ca-bundle2', 'utf8'), // this ca property is optional 
    }), 
} 
try { 
    var options = { 
     SNICallback: function (domain, cb) { 
      if (secureContext[domain]) { 
       if (cb) { 
        cb(null, secureContext[domain]); 
       } else { 
        // compatibility for older versions of node 
        return secureContext[domain]; 
       } 
      } else { 
       throw new Error('No keys/certificates for domain requested'); 
      } 
     }, 
     // must list a default key and cert because required by tls.createServer() 
     key: fs.readFileSync('../path_to_key.pem'), 
     cert: fs.readFileSync('../path_to_cert.crt'), 
    } 
    https.createServer(options, function (req, res) { 
     res.end('Your dynamic SSL server worked!') 
     // Here you can put proxy server routing here to send the request 
     // to the application of your choosing, running on another port. 
     // node-http-proxy is a great npm package for this 
    }).listen(443); 
} catch (err){ 
    console.error(err.message); 
    console.error(err.stack); 
} 

Dentro del servidor puede utilizar nodejs paquete http-proxy para encaminar sus https solicitan a sus diversas aplicaciones.

-1

Solo quería señalar, @clusterfork fue perfecto para mí, pero una actualización del sistema hizo que toda mi solución fallara porque ahora SNICallback está trabajando con 2 parámetros, y una simple actualización del sistema hizo que todo se bloqueara repentinamente. Así que ahora está funcionando de nuevo, ya que SNICallback ahora viene con 2 parámetros, callback de dominio &, y una simple adaptación de código lo hizo funcionar, como dijo @risyasin en los comentarios.

Cuestiones relacionadas