Showing posts with label OpenSSL. Show all posts
Showing posts with label OpenSSL. Show all posts

Thursday, 5 July 2018

Node.js - Using HTTPS + CORS

So, on this blog I've given a Node.js simple web service example before but it was plain vanilla and didn't handle either secure connections with HTTPS or handle this curious protocol called CORS (see below). I remedy that here by given some working code which allows POSTing of json payloads.

So to make your Node.js web service handle https you need to use

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

var options = {
    // create the following two files beforehand with openssl
    // https://stackoverflow.com/questions/12871565/how-to-create-pem-files-for-https-web-server#answer-12907165
    key: fs.readFileSync('key.pem'),
    cert: fs.readFileSync('cert.pem')
};

where you are specifying the private key and the SSL certificate which you must have created before. Switch to your node.js source files directory so openssl.exe creates the files in the right place. A good stack overflow Q&A here shows how to create these files.

CORS Cross-Origin Resource Sharing

Ideally all files and content are delivered from one single web domain (+port). Sometimes a use case is not that simple. Sometimes a web resource needs to be accessed from a different origin. CORS allows this cross origin request. As you can imagine you are opening up a security hole; so in production think carefully about where cross-origin requests might originate and tie down as much as possible. In production, don't use wildcards like in sample code given below! A naughty person could launch a denial of service attack if you allow them! A good CORS guide is here.

Pre-flight request

Today I learnt that some client will send an HTTP OPTIONS request before sending a HTTP POST request; this is known as a "pre-flight request". If you are not using a web server framework then you will need to handle this manually by setting HTTP response headers like the following...

            // IN PRODUCTION DO NOT USE WILDCARDS!!!
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, Accept");

So in the above code I have not tied down Origin but you dear reader must do in production! But this is a blog sample. I have tied down the HTTP methods, only allowing POST and OPTIONS. I have also tied down the headers.

Whilst one should should tie down options as much as possible if you tie down too much your client will assume it has been refused permission and not send the follow-on POST request (in my use case). I had to debug CORS today because my POSTs were not coming through. If the preflight OPTIONS request is not implemented then yes any POST request will not follow on.

Anyway, here is a full working example. The following code runs an HTTPS service at 127.0.0.1:8000 and only allows OPTIONS and GET. Don't forget in production to further restrict the origin and not use wildcards...

'use strict';

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

var options = {
    // create the following two files beforehand with openssl
    // https://stackoverflow.com/questions/12871565/how-to-create-pem-files-for-https-web-server#answer-12907165
    key: fs.readFileSync('key.pem'),
    cert: fs.readFileSync('cert.pem')
};

const port = 8000;

console.log('nversion 0.001n');

//https://stackoverflow.com/questions/5998694/how-to-create-an-https-server-in-node-js#answer-21809393
https.createServer(options, function (request, response) {

    switch (request.method) {
        case "OPTIONS":
            // IN PRODUCTION DO NOT USE WILDCARDS!!!
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, Accept");
            response.end();
            break;
        case "GET":
            console.log(request.url);
            response.end('Hello Node.js Server!');
            break;
        case "POST":
            // IN PRODUCTION DO NOT USE WILDCARDS!!!
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, Accept");
            
            //https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/

            let body = [];
            request.on('data', (chunk) => {
                body.push(chunk);
            }).on('end', () => {
                body = Buffer.concat(body).toString();
                // at this point, `body` has the entire request body stored in it as a string
                console.log('nbody received:nn' + body);

            });

            response.end();
            break;
    }
}).listen(port);

Wednesday, 2 August 2017

Some notes on Ivan Ristic's OpenSSL Cookbook

So Ivan Ristić has donated some chapters of OpenSSL documentation free which is welcome and we thank him for this. From the point of view of an Excel developer, I'm interested in digital signatures, shipping a C++/C# component with a digitally signed licence file to prevent those who have not paid but who have acquired a copy of the executable from running the software.

So, I will give some notes and quotes.

Key Generation

Key algorithm

For SSL keys everyone uses RSA and ECDSA keys are yet to be widely supported by CAs

Key size

When generating a key use a longer length than the default. Bit for bit Eliptic Curve keys are stronger.
Today, 2048-bit RSA keys are considered secure, and that’s what you should use. Aim also to use 2048 bits for DSA keys and at least 224 bits for ECDSA

Passphrase

Using a passphrase with a key is optional, but strongly recommended ... passphrases should be viewed only as a mechanism for protecting private keys when they are not installed on production systems. In other words, it’s all right to keep passphrases on production systems, next to the keys.

Command Line Key Generation

RSA Keys
To generate private key use the following command, new file is fd.key. Don't forget your passphrase!

c:\OpenSSL-Win64\bin\openssl genrsa -aes128 -out fd.key 2048
Generating RSA private key, 2048 bit long modulus
.......+++
..........................................................................+++
e is 65537 (0x10001)
Enter pass phrase for fd.key:
Verifying - Enter pass phrase for fd.key:


To generate corresponding public key use the following command, new file is fd-public.key. Don't forget your passphrase!

c:\OpenSSL-Win64\bin\openssl rsa -in fd.key -pubout -out -fd-public.key
Enter pass phrase for fd.key:
writing RSA key


I skipped showing output because RSA keys are long hence the attraction of elliptic curve keys.
Elliptic Curve Keys
Here how to generate an elliptic curve key.

> openssl ecparam -genkey -name secp256r1 | openssl ec -out ec.key -aes128
using curve name prime256v1 instead of secp256r1
read EC key
writing EC key
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

and to show its output

C:\OpenSSL-Win64\bin> openssl ec -in ec.key -text -noout
read EC key
Enter PEM pass phrase:
Private-Key: (256 bit)
priv:
00:a8:bc:2b:6e:9a:15:98:b5:5b:66:56:4e:8c:54:
ab:1a:df:85:25:60:d4:39:6e:b0:88:4f:ee:ea:fd:
e9:f5:93
pub:
04:8e:8b:a6:6f:97:8b:a7:30:59:72:7d:e1:f2:2e:
bd:7e:7e:ee:61:29:3e:a9:3d:41:2f:da:d0:71:67:
30:63:f8:86:dd:42:bd:0a:7b:67:7b:a1:93:12:61:
d0:aa:14:4e:c4:5e:97:64:7d:ae:75:97:c4:66:42:
87:14:08:d6:01
ASN1 OID: prime256v1
NIST CURVE: P-256

Referencing David DeRosa for extracting public key only

C:\OpenSSL-Win64\bin> openssl ec -in ec.key -pubout -out ec-pub.key
read EC key
Enter PEM pass phrase:
writing EC key

And to show the output of this reduced file use this

C:\OpenSSL-Win64\bin>openssl ec -in ec-pub.key -pubin -text -noout read EC key
Private-Key: (256 bit)
pub:
04:8e:8b:a6:6f:97:8b:a7:30:59:72:7d:e1:f2:2e:
bd:7e:7e:ee:61:29:3e:a9:3d:41:2f:da:d0:71:67:
30:63:f8:86:dd:42:bd:0a:7b:67:7b:a1:93:12:61:
d0:aa:14:4e:c4:5e:97:64:7d:ae:75:97:c4:66:42:
87:14:08:d6:01
ASN1 OID: prime256v1
NIST CURVE: P-256

Obviously keep the file with the private key secret [and not on a blog :) ]. You distribute the public key because that is what your client side digital signature validation code will use.

DSA Keys
I skipped the DSA section as I'm not interested in it.

Signing a licence file

So we give an example licence file which articulates the hardware fingerprint (unique to each machine), customer and the software components sold (or being evaluated). And we have chosen JSON as our file format.

{  
   "hardwareFingerprint":{ 
      "volC":"4715-932C"
   },
   "customer":{
      "name":"W Churchill"
   },
   "softwareLicences":[  
      {  
         "name":"spellChecker",
         "licenceType":"90 day evaluation",
         "expiryDate":"2017-Nov-05"
      },
      {  
         "name":"Chess",
         "licenceType":"paid",
         "expiryDate":"Never"
      }
   ]
}


Links

OpenSSL Cookbook