0
# Security and Integrity
1
2
Security features including SSL configuration, certificate validation, and subresource integrity verification for secure HTTP communications.
3
4
## Capabilities
5
6
### SSL/TLS Configuration
7
8
Configure SSL certificate validation and client certificate authentication:
9
10
```javascript { .api }
11
/**
12
* SSL/TLS configuration options
13
*/
14
interface SSLOptions {
15
strictSSL?: boolean; // Enable/disable SSL certificate validation (default: true)
16
ca?: string | Buffer | string[] | Buffer[]; // Certificate authority certificates
17
cert?: string | Buffer; // Client certificate
18
key?: string | Buffer; // Client private key
19
rejectUnauthorized?: boolean; // Alias for strictSSL (internal use)
20
}
21
```
22
23
**Usage Examples:**
24
25
```javascript
26
const fs = require('fs');
27
const fetch = require('make-fetch-happen');
28
29
// Disable SSL verification (not recommended for production)
30
const response1 = await fetch('https://self-signed.example.com/api', {
31
strictSSL: false
32
});
33
34
// Custom CA certificate
35
const response2 = await fetch('https://internal-api.company.com/data', {
36
ca: fs.readFileSync('./company-ca.pem')
37
});
38
39
// Client certificate authentication
40
const response3 = await fetch('https://secure-api.example.com/data', {
41
cert: fs.readFileSync('./client-cert.pem'),
42
key: fs.readFileSync('./client-key.pem'),
43
ca: fs.readFileSync('./ca-cert.pem')
44
});
45
46
// Multiple CA certificates
47
const response4 = await fetch('https://api.example.com/data', {
48
ca: [
49
fs.readFileSync('./ca1.pem'),
50
fs.readFileSync('./ca2.pem'),
51
fs.readFileSync('./ca3.pem')
52
]
53
});
54
```
55
56
### Environment-Based SSL Configuration
57
58
SSL behavior respects Node.js environment variables:
59
60
```javascript { .api }
61
/**
62
* Environment variable support:
63
* - NODE_TLS_REJECT_UNAUTHORIZED: When set to '0', disables SSL verification
64
* - This affects the default value of strictSSL option
65
*
66
* Priority order:
67
* 1. Explicit strictSSL option in request
68
* 2. NODE_TLS_REJECT_UNAUTHORIZED environment variable
69
* 3. Default (true - SSL verification enabled)
70
*/
71
```
72
73
**Usage Examples:**
74
75
```bash
76
# Disable SSL verification globally (not recommended for production)
77
export NODE_TLS_REJECT_UNAUTHORIZED=0
78
node app.js
79
80
# Or per command
81
NODE_TLS_REJECT_UNAUTHORIZED=0 node app.js
82
```
83
84
```javascript
85
// Environment variable affects default behavior
86
const response = await fetch('https://self-signed.example.com/api');
87
// If NODE_TLS_REJECT_UNAUTHORIZED=0, SSL verification is disabled
88
89
// Explicit override of environment
90
const response2 = await fetch('https://self-signed.example.com/api', {
91
strictSSL: true // Forces SSL verification regardless of environment
92
});
93
```
94
95
### Subresource Integrity (SRI)
96
97
Verify response content integrity using cryptographic hashes:
98
99
```javascript { .api }
100
/**
101
* Subresource Integrity options
102
*/
103
interface IntegrityOptions {
104
integrity?: string; // SRI hash string (sha256-, sha384-, sha512-)
105
algorithms?: string[]; // Allowed hash algorithms for verification
106
size?: number; // Expected content size in bytes
107
}
108
109
/**
110
* Supported SRI hash formats:
111
* - sha256-<base64-hash>
112
* - sha384-<base64-hash>
113
* - sha512-<base64-hash>
114
* - Multiple hashes separated by spaces
115
*/
116
```
117
118
**Usage Examples:**
119
120
```javascript
121
// Verify file integrity with SHA256
122
const response1 = await fetch('https://cdn.example.com/library.js', {
123
integrity: 'sha256-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC'
124
});
125
126
// Multiple hash algorithms (any can match)
127
const response2 = await fetch('https://cdn.example.com/library.js', {
128
integrity: 'sha256-abc123... sha512-def456...'
129
});
130
131
// With size verification
132
const response3 = await fetch('https://cdn.example.com/large-file.zip', {
133
integrity: 'sha256-xyz789...',
134
size: 1024 * 1024 * 50 // Expect 50MB file
135
});
136
137
// Custom algorithms (limits which hashes are accepted)
138
const response4 = await fetch('https://cdn.example.com/file.dat', {
139
integrity: 'sha512-abc123...',
140
algorithms: ['sha512'] // Only accept SHA512 hashes
141
});
142
```
143
144
### Integrity Verification Process
145
146
Understanding how integrity verification works:
147
148
```javascript { .api }
149
/**
150
* Integrity verification process:
151
* 1. Response body is streamed through integrity verification
152
* 2. Hash is calculated as data flows through
153
* 3. Final hash is compared against expected integrity value
154
* 4. If mismatch, request fails with EINTEGRITY error
155
* 5. Verification only occurs on 200 responses
156
*/
157
```
158
159
**Usage Examples:**
160
161
```javascript
162
try {
163
const response = await fetch('https://cdn.example.com/tampered-file.js', {
164
integrity: 'sha256-expected-hash-that-wont-match'
165
});
166
const content = await response.text();
167
} catch (error) {
168
if (error.code === 'EINTEGRITY') {
169
console.log('File integrity verification failed!');
170
console.log('Expected:', error.expected);
171
console.log('Actual:', error.actual);
172
}
173
}
174
175
// Integrity verification with caching
176
const response = await fetch('https://cdn.example.com/library.js', {
177
cachePath: './cache',
178
integrity: 'sha256-abc123...'
179
});
180
// Cached responses are also verified against integrity hash
181
```
182
183
### Certificate Management Patterns
184
185
Common patterns for certificate management:
186
187
```javascript
188
const fs = require('fs');
189
const path = require('path');
190
191
// Certificate loading utility
192
const loadCertificates = (certDir) => {
193
return {
194
ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
195
cert: fs.readFileSync(path.join(certDir, 'client.pem')),
196
key: fs.readFileSync(path.join(certDir, 'client-key.pem'))
197
};
198
};
199
200
// Environment-specific certificate configuration
201
const createSecureFetch = (env) => {
202
const config = {};
203
204
if (env === 'development') {
205
// More permissive for development
206
config.strictSSL = false;
207
} else if (env === 'staging') {
208
// Staging certificates
209
const certs = loadCertificates('./certs/staging');
210
Object.assign(config, certs);
211
} else if (env === 'production') {
212
// Production certificates with strict validation
213
const certs = loadCertificates('./certs/production');
214
Object.assign(config, certs, { strictSSL: true });
215
}
216
217
return fetch.defaults(config);
218
};
219
220
// Certificate rotation handling
221
class CertificateManager {
222
constructor(certDir) {
223
this.certDir = certDir;
224
this.certificates = null;
225
this.lastLoaded = 0;
226
this.refreshInterval = 60 * 60 * 1000; // 1 hour
227
}
228
229
loadCertificates() {
230
const now = Date.now();
231
if (!this.certificates || (now - this.lastLoaded) > this.refreshInterval) {
232
this.certificates = {
233
ca: fs.readFileSync(path.join(this.certDir, 'ca.pem')),
234
cert: fs.readFileSync(path.join(this.certDir, 'client.pem')),
235
key: fs.readFileSync(path.join(this.certDir, 'client-key.pem'))
236
};
237
this.lastLoaded = now;
238
}
239
return this.certificates;
240
}
241
242
createFetch() {
243
const certs = this.loadCertificates();
244
return fetch.defaults(certs);
245
}
246
}
247
248
// Usage
249
const certManager = new CertificateManager('./certs');
250
const secureFetch = certManager.createFetch();
251
```
252
253
### Security Error Handling
254
255
Handle security-related errors appropriately:
256
257
```javascript { .api }
258
/**
259
* Security-related error codes:
260
* - EINTEGRITY: Subresource integrity verification failed
261
* - DEPTH_ZERO_SELF_SIGNED_CERT: Self-signed certificate
262
* - UNABLE_TO_VERIFY_LEAF_SIGNATURE: Certificate verification failed
263
* - CERT_HAS_EXPIRED: Certificate has expired
264
* - CERT_NOT_YET_VALID: Certificate not yet valid
265
* - UNABLE_TO_GET_ISSUER_CERT: Cannot get certificate issuer
266
*/
267
```
268
269
**Usage Examples:**
270
271
```javascript
272
try {
273
const response = await fetch('https://secure-api.example.com/data', {
274
cert: clientCert,
275
key: clientKey,
276
ca: caCert,
277
integrity: 'sha256-expected-hash'
278
});
279
} catch (error) {
280
switch (error.code) {
281
case 'EINTEGRITY':
282
console.log('Response integrity verification failed');
283
// Log security incident
284
break;
285
case 'DEPTH_ZERO_SELF_SIGNED_CERT':
286
console.log('Server uses self-signed certificate');
287
// Decide whether to allow or reject
288
break;
289
case 'CERT_HAS_EXPIRED':
290
console.log('Server certificate has expired');
291
// Alert operations team
292
break;
293
case 'UNABLE_TO_VERIFY_LEAF_SIGNATURE':
294
console.log('Certificate verification failed');
295
// Security error - do not retry
296
break;
297
default:
298
console.log('Security error:', error.message);
299
}
300
}
301
302
// Graceful degradation for certificate issues
303
const fetchWithFallback = async (url, options = {}) => {
304
try {
305
return await fetch(url, options);
306
} catch (error) {
307
if (error.code === 'DEPTH_ZERO_SELF_SIGNED_CERT' &&
308
process.env.NODE_ENV === 'development') {
309
console.warn('Allowing self-signed cert in development');
310
return await fetch(url, { ...options, strictSSL: false });
311
}
312
throw error;
313
}
314
};
315
```
316
317
### Content Security Policies
318
319
Integrate with content security policies and security headers:
320
321
```javascript
322
// Generate SRI hashes for CSP
323
const crypto = require('crypto');
324
325
const generateIntegrityHash = (content, algorithm = 'sha256') => {
326
const hash = crypto.createHash(algorithm);
327
hash.update(content);
328
return `${algorithm}-${hash.digest('base64')}`;
329
};
330
331
// Fetch and generate CSP-compatible integrity hash
332
const response = await fetch('https://cdn.example.com/library.js');
333
const content = await response.text();
334
const integrityHash = generateIntegrityHash(content);
335
336
console.log(`<script src="https://cdn.example.com/library.js"
337
integrity="${integrityHash}"
338
crossorigin="anonymous"></script>`);
339
340
// Verify against known good hashes
341
const knownGoodHashes = {
342
'library.js': 'sha256-abc123...',
343
'framework.js': 'sha256-def456...'
344
};
345
346
const secureResponse = await fetch('https://cdn.example.com/library.js', {
347
integrity: knownGoodHashes['library.js']
348
});
349
```