How do I use a self signed certificate for a HTTPS Node.js server?

前端 未结 5 1109
别那么骄傲
别那么骄傲 2020-11-28 19:16

I have started writing a wrapper for an API which requires all requests to be over HTTPS. Instead of making requests to the actual API while I am developing and testing it I

相关标签:
5条回答
  • 2020-11-28 19:30

    This procedure allows you to create both a certificate authority & a certificate :

    1. grab this ca.cnf file to use as a configuration shortcut :

      wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/ca.cnf


    1. create a new certificate authority using this configuration :

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


    1. now that we have our certificate authority in ca-key.pem and ca-cert.pem, let's generate a private key for the server :

      openssl genrsa -out key.pem 4096


    1. grab this server.cnf file to use as a configuration shortcut :

      wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/server.cnf


    1. generate the certificate signing request using this configuration :

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


    1. sign the request :

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

    I found this procedure here, along with more information on how to use these certificates.

    0 讨论(0)
  • 2020-11-28 19:31

    Try adding this to your request options

    var options = {
      host: 'localhost',
      port: 8000,
      path: '/api/v1/test',
      // These next three lines
      rejectUnauthorized: false,
      requestCert: true,
      agent: false
    };
    
    0 讨论(0)
  • 2020-11-28 19:33

    Update (Nov 2018): Do you need self-signed certs?

    Or would real certificates get the job done better? Have you considered any of these?

    • Let's Encrypt via Greenlock.js
    • Let's Encrypt via https://greenlock.domains
    • Localhost relay service such as https://telebit.cloud

    (Note: Let's Encrypt can also issue certificates to private networks)

    ScreenCast

    https://coolaj86.com/articles/how-to-create-a-csr-for-https-tls-ssl-rsa-pems/

    Full, Working example

    • creates certificates
    • runs node.js server
    • no warnings or errors in node.js client
    • no warnings or errors in cURL

    https://github.com/coolaj86/nodejs-self-signed-certificate-example

    Using localhost.greenlock.domains as an example (it points to 127.0.0.1):

    server.js

    'use strict';
    
    var https = require('https')
      , port = process.argv[2] || 8043
      , fs = require('fs')
      , path = require('path')
      , server
      , options
      ;
    
    require('ssl-root-cas')
      .inject()
      .addFile(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem'))
      ;
    
    options = {
      // this is ONLY the PRIVATE KEY
      key: fs.readFileSync(path.join(__dirname, 'server', 'privkey.pem'))
      // You DO NOT specify `ca`, that's only for peer authentication
    //, ca: [ fs.readFileSync(path.join(__dirname, 'server', 'my-private-root-ca.cert.pem'))]
      // This should contain both cert.pem AND chain.pem (in that order) 
    , cert: fs.readFileSync(path.join(__dirname, 'server', 'fullchain.pem'))
    };
    
    
    function app(req, res) {
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello, encrypted world!');
    }
    
    server = https.createServer(options, app).listen(port, function () {
      port = server.address().port;
      console.log('Listening on https://127.0.0.1:' + port);
      console.log('Listening on https://' + server.address().address + ':' + port);
      console.log('Listening on https://localhost.greenlock.domains:' + port);
    });
    

    client.js

    'use strict';
    
    var https = require('https')
      , fs = require('fs')
      , path = require('path')
      , ca = fs.readFileSync(path.join(__dirname, 'client', 'my-private-root-ca.cert.pem'))
      , port = process.argv[2] || 8043
      , hostname = process.argv[3] || 'localhost.greenlock.domains'
      ;
    
    var options = {
      host: hostname
    , port: port
    , path: '/'
    , ca: ca
    };
    options.agent = new https.Agent(options);
    
    https.request(options, function(res) {
      res.pipe(process.stdout);
    }).end();
    

    And the script that makes the certificate files:

    make-certs.sh

    #!/bin/bash
    FQDN=$1
    
    # make directories to work from
    mkdir -p server/ client/ all/
    
    # Create your very own Root Certificate Authority
    openssl genrsa \
      -out all/my-private-root-ca.privkey.pem \
      2048
    
    # Self-sign your Root Certificate Authority
    # Since this is private, the details can be as bogus as you like
    openssl req \
      -x509 \
      -new \
      -nodes \
      -key all/my-private-root-ca.privkey.pem \
      -days 1024 \
      -out all/my-private-root-ca.cert.pem \
      -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com"
    
    # Create a Device Certificate for each domain,
    # such as example.com, *.example.com, awesome.example.com
    # NOTE: You MUST match CN to the domain name or ip address you want to use
    openssl genrsa \
      -out all/privkey.pem \
      2048
    
    # Create a request from your Device, which your Root CA will sign
    openssl req -new \
      -key all/privkey.pem \
      -out all/csr.pem \
      -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}"
    
    # Sign the request from Device with your Root CA
    openssl x509 \
      -req -in all/csr.pem \
      -CA all/my-private-root-ca.cert.pem \
      -CAkey all/my-private-root-ca.privkey.pem \
      -CAcreateserial \
      -out all/cert.pem \
      -days 500
    
    # Put things in their proper place
    rsync -a all/{privkey,cert}.pem server/
    cat all/cert.pem > server/fullchain.pem         # we have no intermediates in this case
    rsync -a all/my-private-root-ca.cert.pem server/
    rsync -a all/my-private-root-ca.cert.pem client/
    
    # create DER format crt for iOS Mobile Safari, etc
    openssl x509 -outform der -in all/my-private-root-ca.cert.pem -out client/my-private-root-ca.crt
    

    For example:

    bash make-certs.sh 'localhost.greenlock.domains'
    

    Hopefully this puts the nail in the coffin on this one.

    And some more explanation: https://github.com/coolaj86/node-ssl-root-cas/wiki/Painless-Self-Signed-Certificates-in-node.js

    Install private cert on iOS Mobile Safari

    You need to create a copy of the root ca certificate a DER format with a .crt extension:

    # create DER format crt for iOS Mobile Safari, etc
    openssl x509 -outform der -in all/my-private-root-ca.cert.pem -out client/my-private-root-ca.crt
    

    Then you can simply serve that file with your webserver. When you click the link you should be asked if you want to install the certificate.

    For an example of how this works you can try installing MIT's Certificate Authority: https://ca.mit.edu/mitca.crt

    Related Examples

    • https://github.com/coolaj86/nodejs-ssl-example
    • https://github.com/coolaj86/nodejs-ssl-trusted-peer-example
    • https://github.com/coolaj86/node-ssl-root-cas
    • https://github.com/coolaj86/nodejs-https-sni-vhost-example
      • (Multiple vhosts with SSL on the same server)
    • https://telebit.cloud
      • (get REAL SSL certs you can use TODAY for testing on localhost)
    0 讨论(0)
  • 2020-11-28 19:38

    Try adding

      agent: false,
      rejectUnauthorized: false
    
    0 讨论(0)
  • 2020-11-28 19:40

    Your key generation looks okay. You shouldn't need a ca because you aren't rejecting unsigned requests.

    Add .toString() to the end of your readFileSync methods so that you are actually passing a string, not a file object.

    0 讨论(0)
提交回复
热议问题