banner
niracler

niracler

长门大明神会梦到外星羊么?
github
email
steam_profiles
douban
nintendo switch
telegram

Optimizing TLS performance of websites: Solving certificate verification issues through OCSP Stapling in Node.js HTTP Server.

I always feel that there is a better way, so I'm throwing this out there as a starting point. Welcome to criticize.

Requirements#

In the domestic network environment, the TLS security certificate of a website may be unable to access the Online Certificate Status Protocol (OCSP) server due to DNS issues. OCSP is responsible for real-time verification of the revocation status of SSL/TLS certificates in the network.

For example, when we try to access a website that uses schannel (Windows native TLS library) using the curl command-line tool, we may encounter an error similar to the following due to the certificate status not being verified online:

I am using a digicert certificate here, and the ocsp server is ocsp.digicert.com. In the case where the server is blocked or cannot be accessed, the certificate status verification fails. If you have used a let's encrypt certificate, you should be more affected by this~

$ curl -v https://hub.x-cmd.com
*   Trying 47.113.155.92:443...
* Connected to hub.x-cmd.com (47.113.155.92) port 443 (#0)
* schannel: disabled automatic use of client certificate
* ALPN: offers http/1.1
* schannel: next InitializeSecurityContext failed: Unknown error (0x80092013) - Revocation function was unable to check revocation because the revocation server was offline.
* Closing connection 0
* schannel: shutting down SSL/TLS connection with hub.x-cmd.com port 443
curl: (35) schannel: next InitializeSecurityContext failed: Unknown error (0x80092013) - Revocation function was unable to check revocation because the revocation server was offline.

ps. curl with schannel version will enable "certificate status verification" by default, while curl with openssl version will not. So even if the verification fails, curl with openssl version can still obtain the result normally.

Overview of the Solution: Introducing OCSP Stapling#

OCSP Stapling is an optimized method for online certificate checking. It allows the website server to obtain and "staple" the OCSP authentication result in advance instead of each client querying the OCSP server separately. This not only reduces the delay in the handshake process but also reduces the load on the OCSP server.

Working Mechanism of OCSP Stapling#

In the traditional mode, the client needs to communicate with the CA's OCSP server during the TLS handshake process to confirm the validity of the server certificate. OCSP Stapling simplifies this process in the following way:

  1. During the TLS handshake request, the client requests the server to provide the certificate status.
  2. The server periodically obtains the signed certificate status response from the CA's OCSP server and caches it.
  3. When there is a new TLS handshake request, the server sends the cached OCSP response together with the certificate to the client.

This mechanism avoids the need for the client to directly request the OCSP server, reducing the delay in the TLS handshake. At the same time, it reduces the load on the OCSP server because it no longer needs to provide a response for each client request. (And don't worry about the ocsp server being blocked)

The following is a simplified diagram of this process:

Mermaid Loading...

Here is a better diagram from Alibaba Cloud:
Better Diagram

Enabling OCSP Stapling using the ocsp library#

We can use the ocsp library to implement OCSP Stapling on a Node.js server. Since the library is no longer maintained, TypeScript users may need to refer to the fix in this PR. After installation, you can configure the server as follows:

On the basis of the original node server, add the server's OCSPRequest event and return the OSCP information in the event.

import ocsp from "ocsp"

// Create cache for OCSP (it'll be used to respond to OCSP stapling requests)
const cache = new ocsp.Cache()

server.on('OCSPRequest', (cert, issuer, cb) => {
    ocsp.getOCSPURI(cert, function (err, uri) {
        if (err) return cb(err, Buffer.alloc(0))
        if (uri === null || uri === undefined) return cb(null, Buffer.alloc(0))

        const req = ocsp.request.generate(cert, issuer)
        cache.probe(req.id.toString(), function (err, cached) {
            if (err) return cb(err, Buffer.alloc(0))
            if (cached !== false) return cb(null, cached.response)

            const options = {
                url: uri,
                ocsp: Buffer.from(req.data)
            }

            cache.request(req.id, options, cb)
        })
    })
})

Potential Issues#

  1. The cached OCSP information on the server may expire and needs to be updated regularly. The ocsp library has already taken care of this.
  2. There may be network issues between the server and the CA's OCSP server, resulting in the inability to obtain OCSP information. In this case, the server should degrade to the client requesting the OCSP server. The server should not reject client requests because it cannot obtain OCSP information.

References#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.