Подтвердить что ты не робот

Можно ли динамически вернуть сертификат SSL в NodeJS?

Я хочу динамически возвращать информацию о сертификате ssl в моем приложении NodeJS. У меня есть два доменных имени, связанных с тем же приложением node. Я вижу только, что настройки ssl могут быть указаны при создании сервера. Можно ли динамически возвращать сертификаты ssl на основе запрошенного URL?

В противном случае, если вместо этого я должен создать экземпляр второго экземпляра на другом порту, смогу ли я прозрачно подключить каждый запрос к исходному порту? Могу ли я показать, что он не работает на втором порту?

Спасибо, Джефф

4b9b3361

Ответ 1

Да, это возможно сделать с одним сервером. Но оговорка заключается в том, что она работает на клиентах, поддерживающих SNI - это самые современные браузеры.

Вот как вы это делаете:

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

Это работает, потому что параметры для https похожи на tls.createServer(). Убедитесь, что вы включили все необходимые промежуточные и корневые сертификаты CA в вызов crypto.createCredentials. Также, если у вас есть пакет CA, разделите их на несколько одиночных crt файлов, прежде чем использовать их, поскольку "ca" принимает массив сертификатов.

Ответ 2

crypto.createCredentials() устарел, поэтому используйте tls.createSecureContext().

tls.createServer() должен иметь key и cert в параметрах, потому что они требуются в руководстве. Возможно, tls.createServer() использует эти параметры как значения по умолчанию в случае, если SNICallback не поддерживается.

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

Внутри сервера вы можете использовать пакет nodejs http-proxy для маршрутизации вашего запроса https в различные приложения.

Ответ 3

Я просто хотел указать на то, что @clusterfork идеально подходит для меня, но системное обновление полностью разрушило ваше решение, потому что теперь SNICallback работает с двумя параметрами, и простое обновление системы внезапно сработало. Итак, теперь он работает, так как SNICallback теперь имеет 2 параметра, домен и обратный вызов, а простая адаптация кода заставила его работать, как сказал @risyasin в комментариях.