@ladjs/shared-config
Advanced tools
+89
-0
@@ -14,2 +14,76 @@ const fs = require('node:fs'); | ||
| // | ||
| // Hardened TLS cipher suites (only AEAD ciphers with forward secrecy). | ||
| // | ||
| // Ordered by security level per NCSC/internet.nl guidelines: | ||
| // "Good" = ECDHE + AEAD, "Sufficient" = DHE + AEAD | ||
| // | ||
| // Excludes: | ||
| // - RSA key exchange (no forward secrecy) | ||
| // - CBC mode ciphers | ||
| // - ARIA ciphers | ||
| // - CCM/CCM8 ciphers | ||
| // - DSS authentication | ||
| // | ||
| // TLS 1.3 ciphers are always enabled and not affected by this setting. | ||
| // | ||
| const TLS_CIPHERS = [ | ||
| 'ECDHE-ECDSA-AES256-GCM-SHA384', | ||
| 'ECDHE-RSA-AES256-GCM-SHA384', | ||
| 'ECDHE-ECDSA-AES128-GCM-SHA256', | ||
| 'ECDHE-RSA-AES128-GCM-SHA256', | ||
| 'ECDHE-ECDSA-CHACHA20-POLY1305', | ||
| 'ECDHE-RSA-CHACHA20-POLY1305', | ||
| 'DHE-RSA-AES256-GCM-SHA384', | ||
| 'DHE-RSA-AES128-GCM-SHA256', | ||
| 'DHE-RSA-CHACHA20-POLY1305' | ||
| ].join(':'); | ||
| // | ||
| // Compat cipher list: Adds CBC ciphers with forward secrecy for | ||
| // backward compatibility with older clients (e.g. TLS 1.0/1.1). | ||
| // Still excludes RSA key exchange (no forward secrecy). | ||
| // | ||
| const TLS_COMPAT_CIPHERS = [ | ||
| // AEAD ciphers first (preferred) | ||
| 'ECDHE-ECDSA-AES256-GCM-SHA384', | ||
| 'ECDHE-RSA-AES256-GCM-SHA384', | ||
| 'ECDHE-ECDSA-AES128-GCM-SHA256', | ||
| 'ECDHE-RSA-AES128-GCM-SHA256', | ||
| 'ECDHE-ECDSA-CHACHA20-POLY1305', | ||
| 'ECDHE-RSA-CHACHA20-POLY1305', | ||
| 'DHE-RSA-AES256-GCM-SHA384', | ||
| 'DHE-RSA-AES128-GCM-SHA256', | ||
| 'DHE-RSA-CHACHA20-POLY1305', | ||
| // CBC ciphers with forward secrecy (for TLS 1.0/1.1 compat) | ||
| 'ECDHE-ECDSA-AES256-SHA384', | ||
| 'ECDHE-RSA-AES256-SHA384', | ||
| 'ECDHE-ECDSA-AES128-SHA256', | ||
| 'ECDHE-RSA-AES128-SHA256', | ||
| 'ECDHE-ECDSA-AES256-SHA', | ||
| 'ECDHE-RSA-AES256-SHA', | ||
| 'ECDHE-ECDSA-AES128-SHA', | ||
| 'ECDHE-RSA-AES128-SHA', | ||
| 'DHE-RSA-AES256-SHA256', | ||
| 'DHE-RSA-AES128-SHA256', | ||
| 'DHE-RSA-AES256-SHA', | ||
| 'DHE-RSA-AES128-SHA' | ||
| ].join(':'); | ||
| // | ||
| // Signature algorithms for TLS 1.2 key exchange. | ||
| // Excludes SHA-1 and SHA-224 (outdated per internet.nl/NCSC guidelines). | ||
| // | ||
| const TLS_SIGALGS = [ | ||
| 'ecdsa_secp256r1_sha256', | ||
| 'ecdsa_secp384r1_sha384', | ||
| 'ecdsa_secp521r1_sha512', | ||
| 'rsa_pss_rsae_sha256', | ||
| 'rsa_pss_rsae_sha384', | ||
| 'rsa_pss_rsae_sha512', | ||
| 'rsa_pkcs1_sha256', | ||
| 'rsa_pkcs1_sha384', | ||
| 'rsa_pkcs1_sha512' | ||
| ].join(':'); | ||
| // eslint-disable-next-line complexity | ||
@@ -27,2 +101,14 @@ function sharedConfig(prefix, env = process.env.NODE_ENV || 'development') { | ||
| if (semver.gte(process.version, 'v18.16.0')) ssl.ecdhCurve = 'auto'; | ||
| // | ||
| // Hardened TLS options: | ||
| // - Enforce server cipher suite preference order | ||
| // - Only allow AEAD ciphers with forward secrecy | ||
| // - Exclude weak signature algorithms (SHA-1, SHA-224) | ||
| // | ||
| ssl.honorCipherOrder = true; | ||
| ssl.ciphers = TLS_CIPHERS; | ||
| ssl.sigalgs = TLS_SIGALGS; | ||
| ssl.minVersion = 'TLSv1.2'; | ||
| for (const key of validKeys) { | ||
@@ -157,1 +243,4 @@ ssl[key.toLowerCase()] = fs.readFileSync( | ||
| module.exports = sharedConfig; | ||
| module.exports.TLS_CIPHERS = TLS_CIPHERS; | ||
| module.exports.TLS_COMPAT_CIPHERS = TLS_COMPAT_CIPHERS; | ||
| module.exports.TLS_SIGALGS = TLS_SIGALGS; |
+1
-1
| { | ||
| "name": "@ladjs/shared-config", | ||
| "description": "Shared configuration for Lad's API and Web servers", | ||
| "version": "9.1.4", | ||
| "version": "10.0.0", | ||
| "author": "Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com/)", | ||
@@ -6,0 +6,0 @@ "bugs": { |
12467
26.08%229
57.93%