понедельник, 15 июля 2019 г.

Создание Node.js HTTPS, TLS/SSL сертификатов.

Для работы с HTTPS, TLS/SSL необходимо произвести следующие действия:

1) Создать "центр сертификации" (CA - Certificate Authority), который позволит создавать и проверять "самоподписанные сертфикаты" (Self-Signed SSL Certificate).
2) Создать "приватный ключ" (Private key) для подписи сертификатов.
3) С помощью "приватного ключа" (Private key) создать "запрос на подпись сертификата" (CSR - Certificate signing request).
4) С помощью "приватного ключа" (Private key) и "запроса на подпись сертификата" (CSR - Certificate signing request) создать сам "сертификат" (Cert - Certificate).

Создание "центра сертификации" (Certificate Authority).

Для упрощения процесса скопируйте эти настройки в файл "ca.cnf" и пропишите в них ваши значения.

[ ca ]
default_ca      = CA_default

[ CA_default ]
serial = ca-serial
crl = ca-crl.pem
database = ca-database.txt
name_opt = CA_default
cert_opt = CA_default
default_crl_days = 9999
default_md = md5

[ req ]
default_bits           = 4096
days                   = 9999
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no
output_password        = password

[ req_distinguished_name ]
C                      = US
ST                     = MA
L                      = Boston
O                      = Example Co
OU                     = techops
CN                     = ca
emailAddress           = certs@example.com

[ req_attributes ]
challengePassword      = test

Далее в командной строке вашего терминала выполните такую команду:

openssl req -new -x509 -days 9999 -config ca.cnf -keyout ca-key.pem -out ca-crt.pem

В результате вы создадите файлы "центра сертификации": ca-key.pem и ca-crt.pem.

Теперь создадим "приватный ключ" (Private key) для сервера Node.js с помощью следующей команды:

openssl genrsa -out server-key.pem 4096

В результате вы создадите файл server-key.pem.

Теперь создадим "запрос на подпись сертификата" (CSR - Certificate signing request).

Для упрощения процесса скопируйте эти настройки в файл "server.cnf" и пропишите в них ваши значения.

[ req ]
default_bits           = 4096
days                   = 9999
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no
x509_extensions        = v3_ca

[ req_distinguished_name ]
C                      = US
ST                     = MA
L                      = Boston
O                      = Example Co
OU                     = techops
CN                     = localhost
emailAddress           = certs@example.com

[ req_attributes ]
challengePassword      = password

[ v3_ca ]
authorityInfoAccess = @issuer_info

[ issuer_info ]
OCSP;URI.0 = http://ocsp.example.com/
caIssuers;URI.0 = http://example.com/ca.cert

После этого выполните команду:

openssl req -new -config server.cnf -key server-key.pem -out server-csr.pem

В результате вы создадите файл server-csr.pem.

Далее подпишем "запрос на подпись сертификата" (CSR - Certificate signing request) нашим "приватным ключем" (Private key) для создания итогового "сертификата" (Cert - Certificate) нашего Node.js HTTPS, TLS/SSL сервера, выполнив команду:

openssl x509 -req -extfile server.cnf -days 999 -passin "pass:password" -in server-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out server-crt.pem

Обратите внимание на заданный в команде пароль: "pass:password".

В результате вы создадите файл server-crt.pem.

Теперь созданный сертификат готов для использования не сервере.

Создадим файл "server.js" и пропишем в нем данный код для создания HTTPS сервера:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('server-key.pem'),
    cert: fs.readFileSync('server-crt.pem'),
    ca: fs.readFileSync('ca-crt.pem')
};

https.createServer(options, function (req, res) {
    console.log(new Date() + ' ' +  req.connection.remoteAddress + ' ' +  req.method + ' '+ req.url);
    res.writeHead(200);
    res.end("Hello world!");
}).listen(443, '127.0.0.1');

Проверим, как работает наш сервер при получения запроса от браузера, перейдя в браузере по адресу "127.0.0.1:443".

Не забудьте добавить в вашу операционную систему созданный нами "центр сертификации" (CA - Certificate Authority) путем установки файла "ca-crt.pem" и пометки его, как доверенного.

После проверки работы сервера через браузер создадим HTTPS-клиент для Node.js, который мог бы соединяться с нашим HTTPS-сервером c проверкой сертификата сервера через созданный нами "центр сертификации" (CA - Certificate Authority).

Создадим файл "client.js" и пропишем в нем данный код для создания HTTPS клиента:

var https = require('https');
var fs = require('fs');

var options = {
    method: 'GET',
    hostname: 'localhost',
    port: 443,
    path: '/',
    ca: fs.readFileSync('ca-crt.pem')
};

var req = https.request(options, function (res) {
    res.on('data', function (data) {
        process.stdout.write(data);
    });
});

req.end();

Обратите внимание, что в options мы добавили свойство "ca", в котором прописан наш файл  "центра сертификации" (CA - Certificate Authority) для того, чтобы наш клиент мог доверять "публичному ключу" (Public key), который он получит от сервера при подключении к нему.

Теперь выполните код подключения клиента к серверу и в консоли командной строки вы увидите надпись: "Hello world!".

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

Мы сделаем два сертификата для того, чтобы иметь возможность делать запросы к серверу из двух разных клиентов.

Создадим каждому клиенту свой "приватный ключ" (Private key) командами:

openssl genrsa -out client1-key.pem 4096

openssl genrsa -out client2-key.pem 4096

В результате вы создадите файл client1-key.pem и файл client2-key.pem.

Далее создадим два "запроса на подпись сертификата" (CSR - Certificate signing request).

Для упрощения процесса скопируйте эти настройки в файл "client1.cnf" и пропишите в них ваши значения.

[ req ]
default_bits           = 4096
days                   = 9999
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no
x509_extensions        = v3_ca

[ req_distinguished_name ]
C                      = US
ST                     = MA
L                      = Boston
O                      = Example Co
OU                     = techops
CN                     = client1
emailAddress           = certs@example.com

[ req_attributes ]
challengePassword      = password

[ v3_ca ]
authorityInfoAccess = @issuer_info

[ issuer_info ]
OCSP;URI.0 = http://ocsp.example.com/
caIssuers;URI.0 = http://example.com/ca.cert

А настройки ниже скопируйте в файл "client2.cnf" и пропишите в них ваши значения.

[ req ]
default_bits           = 4096
days                   = 9999
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no
x509_extensions        = v3_ca

[ req_distinguished_name ]
C                      = US
ST                     = MA
L                      = Boston
O                      = Example Co
OU                     = techops
CN                     = client2
emailAddress           = certs@example.com

[ req_attributes ]
challengePassword      = password

[ v3_ca ]
authorityInfoAccess = @issuer_info

[ issuer_info ]
OCSP;URI.0 = http://ocsp.example.com/
caIssuers;URI.0 = http://example.com/ca.cert

"Запросы на подпись сертификата" (CSR - Certificate signing request) создадим с помощью пары команд:

openssl req -new -config client1.cnf -key client1-key.pem -out client1-csr.pem

openssl req -new -config client2.cnf -key client2-key.pem -out client2-csr.pem

В результате вы создадите файл client1-csr.pem и файл client2-csr.pem.

Теперь подпишем "запросы на подпись сертификата" (CSR - Certificate signing request) нашим "приватным ключем" (Private key) для создания итоговых "сертификатов" (Cert - Certificate) наших Node.js HTTPS, TLS/SSL клиентов, выполнив команду:

openssl x509 -req -extfile client1.cnf -days 999 -passin "pass:password" -in client1-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out client1-crt.pem


openssl x509 -req -extfile client2.cnf -days 999 -passin "pass:password" -in client2-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out client2-crt.pem

В результате вы создадите файл client1-crt.pem и файл client2-crt.pem.

Для того, чтобы убедиться, что мы все сделали верно проверим наши сертификаты, выполнив команды:

openssl verify -CAfile ca-crt.pem client1-crt.pem

openssl verify -CAfile ca-crt.pem client2-crt.pem

Такую же проверку вы можете сделать и для сертификата, который вы создали для сервера, выполнив команду:

openssl verify -CAfile ca-crt.pem server-crt.pem

Если вы все сделали верно, то вы получите "OK" в результате проверки.

Теперь напишем код сервера и клиента, использующего каждый свой сертификат.

Добавим в код сервера свойства requestCert и rejectUnauthorized, требующие, чтобы клиент всегда предоставлял серверу свой сертификат, изменив код в файле "server.js" так:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('server-key.pem'),
    cert: fs.readFileSync('server-crt.pem'),
    ca: fs.readFileSync('ca-crt.pem'),
    requestCert: true, 
    rejectUnauthorized: true
};

https.createServer(options, function (req, res) {
    console.log(new Date() + ' '  + req.connection.remoteAddress + ' ' + req.socket.getPeerCertificate().subject.CN +  ' '  + req.method +  ' ' +  req.url);
    res.writeHead(200);
    res.end("Hello world!");
}).listen(443);

Теперь, если вы попробуйте подключиться к серверу из клиента, то подключение клиента будет отвергнуто сервером, поскольку в данный момент клиент еще не умеет передавать серверу свой сертификат.

В итоге Node.js выдаст сообщение об ошибке "socket hangup error" из-за того, что TLS не будет соблюдено.

Поэтому, чтобы все заработало мы добавим в код клиента в файле "client.js" опции key и cert так:

var https = require('https');
var fs = require('fs');

var options = {
    method: 'GET',
    hostname: 'localhost',
    port: 443,
    path: '/',
    key: fs.readFileSync('client1-key.pem'), 
    cert: fs.readFileSync('client1-crt.pem'), 
    ca: fs.readFileSync('ca-crt.pem')
};

var req = https.request(options, function (res) {
    res.on('data', function(data) {
        process.stdout.write(data);
    });
});

req.on('error', function(e) {
    console.error(e);
});

req.end();

После этого выполните подключение клиента к серверу и сервер в ответ вернет "Hello world!".
В консоли сервера в этом случае вы увидите информации о подключении клиента и его "Common Name" из переданного серверу сертификата.

Поменяйте в коде клиента сертификат client1 на сертификат client2 и вы увидите, что клиент со вторым сертификатом также подключается к серверу.

Теперь проведем "отзыв сертификата" (CR - Certificate Revocation).

Для отзыва второго сертификата клиента мы создадим "список отозванных сертификатов" (CRL - Certificate Revocation List).

Чтобы это сделать создайте пустой текстовый файл "ca-database.txt", символизирующий базу данных.

Далее выполните команду для отзыва второго сертификата клиента client2-crt.pem:

openssl ca -revoke client2-crt.pem -keyfile ca-key.pem -config ca.cnf -cert ca-crt.pem -passin "pass:password"

Обратите внимание на заданный в команде пароль: "pass:password".

После этого выполните команду для обновления "списка отозванных сертификатов" (CRL - Certificate Revocation List):

openssl ca -keyfile ca-key.pem -cert ca-crt.pem -config ca.cnf -gencrl -out ca-crl.pem -passin "pass:password"

Наконец добавьте в опции сервера свойство crl для получения доступа к "списку отозванных сертификатов" (CRL - Certificate Revocation List), изменив код так:

var https = require('https');
var fs = require('fs'); 
var options = { 
    key: fs.readFileSync('server-key.pem'), 
    cert: fs.readFileSync('server-crt.pem'), 
    ca: fs.readFileSync('ca-crt.pem'), 
    crl: fs.readFileSync('ca-crl.pem'), 
    requestCert: true, 
    rejectUnauthorized: true 
}; 

https.createServer(options, function (req, res) { 
    console.log(new Date()+ ' ' + req.connection.remoteAddress + ' ' + req.socket.getPeerCertificate().subject.CN + ' ' + req.method + ' ' + req.url); 
    res.writeHead(200); 
    res.end("Hello world!"); 
}).listen(443);

После этого сервер будет учитывать "список отозванных сертификатов" (CRL - Certificate Revocation List) и принимать запрос от клиента с сертификатом client1-crt.pem и отвергать запросы клиента с сертификатом client2-crt.pem.

Таким образом, мы научились создавать самоподписанные сертификаты для сервера и проверять сертификаты, приходящие от клиентов. Дополнительно к этому мы научились отзывать сертификаты.

Поскольку в сертификатах содержится имя клиента Common Name, то мы также можем использовать их для идентификации каждого клиента на нашем сервере.

1 комментарий:

  1. If you're attempting to lose kilograms then you have to get on this brand new tailor-made keto meal plan.

    To create this service, certified nutritionists, personal trainers, and professional cooks united to develop keto meal plans that are productive, suitable, price-efficient, and fun.

    Since their grand opening in early 2019, hundreds of individuals have already transformed their body and health with the benefits a proper keto meal plan can offer.

    Speaking of benefits: in this link, you'll discover eight scientifically-confirmed ones offered by the keto meal plan.

    ОтветитьУдалить