0
# Security and SSL
1
2
Security and SSL support provides comprehensive HTTPS/TLS encryption, client certificate authentication, security headers, and protocol configuration for secure web applications.
3
4
## SSL Connection Factory
5
6
The `SslConnectionFactory` enables SSL/TLS encryption for HTTP connections.
7
8
```java { .api }
9
public class SslConnectionFactory extends AbstractConnectionFactory
10
implements ConnectionFactory.Detecting, ConnectionFactory.Configuring {
11
12
// Constructors
13
public SslConnectionFactory();
14
public SslConnectionFactory(String nextProtocol);
15
public SslConnectionFactory(SslContextFactory.Server sslContextFactory, String nextProtocol);
16
17
// SSL Context Factory
18
public SslContextFactory.Server getSslContextFactory();
19
public void setSslContextFactory(SslContextFactory.Server sslContextFactory);
20
21
// Protocol configuration
22
public String getNextProtocol();
23
public void setNextProtocol(String nextProtocol);
24
25
// Buffer configuration
26
public boolean isDirectBuffersForEncryption();
27
public void setDirectBuffersForEncryption(boolean useDirectBuffers);
28
public boolean isDirectBuffersForDecryption();
29
public void setDirectBuffersForDecryption(boolean useDirectBuffers);
30
31
// Connection creation
32
public Connection newConnection(Connector connector, EndPoint endPoint);
33
public EndPoint configure(EndPoint endPoint, Connector connector,
34
ConnectionMetaData connectionMetaData);
35
}
36
```
37
38
## SslContextFactory.Server
39
40
Server-side SSL context factory for configuring SSL/TLS settings.
41
42
```java { .api }
43
public class SslContextFactory.Server extends SslContextFactory {
44
// Keystore configuration
45
public void setKeyStorePath(String keyStorePath);
46
public String getKeyStorePath();
47
public void setKeyStoreType(String keyStoreType);
48
public String getKeyStoreType();
49
public void setKeyStorePassword(String keyStorePassword);
50
public void setKeyManagerPassword(String keyManagerPassword);
51
52
// Truststore configuration
53
public void setTrustStorePath(String trustStorePath);
54
public String getTrustStorePath();
55
public void setTrustStoreType(String trustStoreType);
56
public String getTrustStoreType();
57
public void setTrustStorePassword(String trustStorePassword);
58
59
// Client authentication
60
public boolean getWantClientAuth();
61
public void setWantClientAuth(boolean wantClientAuth);
62
public boolean getNeedClientAuth();
63
public void setNeedClientAuth(boolean needClientAuth);
64
65
// Protocol configuration
66
public String[] getIncludeProtocols();
67
public void setIncludeProtocols(String... protocols);
68
public String[] getExcludeProtocols();
69
public void setExcludeProtocols(String... protocols);
70
71
// Cipher suite configuration
72
public String[] getIncludeCipherSuites();
73
public void setIncludeCipherSuites(String... cipherSuites);
74
public String[] getExcludeCipherSuites();
75
public void setExcludeCipherSuites(String... cipherSuites);
76
77
// SNI configuration
78
public boolean isSniRequired();
79
public void setSniRequired(boolean sniRequired);
80
public String[] getSniHostCheck();
81
public void setSniHostCheck(String... hosts);
82
83
// Session configuration
84
public int getSslSessionCacheSize();
85
public void setSslSessionCacheSize(int sslSessionCacheSize);
86
public int getSslSessionTimeout();
87
public void setSslSessionTimeout(int sslSessionTimeout);
88
89
// OCSP configuration
90
public boolean isEnableOCSP();
91
public void setEnableOCSP(boolean enableOCSP);
92
public String getOcspResponderURL();
93
public void setOcspResponderURL(String ocspResponderURL);
94
}
95
```
96
97
## Basic HTTPS Setup
98
99
```java
100
public class BasicHTTPSServer {
101
102
public void createHTTPSServer() throws Exception {
103
Server server = new Server();
104
105
// Create SSL context factory
106
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
107
108
// Configure keystore
109
sslContextFactory.setKeyStorePath("keystore.jks");
110
sslContextFactory.setKeyStorePassword("keystorepassword");
111
sslContextFactory.setKeyManagerPassword("keymanagerpassword");
112
113
// Create HTTP configuration for HTTPS
114
HttpConfiguration httpsConfig = new HttpConfiguration();
115
httpsConfig.setSecureScheme("https");
116
httpsConfig.setSecurePort(8443);
117
httpsConfig.addCustomizer(new SecureRequestCustomizer());
118
119
// Create HTTPS connector
120
ServerConnector httpsConnector = new ServerConnector(server,
121
new SslConnectionFactory(sslContextFactory, "http/1.1"),
122
new HttpConnectionFactory(httpsConfig));
123
httpsConnector.setPort(8443);
124
125
server.addConnector(httpsConnector);
126
127
// Set handler
128
server.setHandler(new SimpleHandler());
129
130
server.start();
131
server.join();
132
}
133
}
134
```
135
136
## Advanced SSL Configuration
137
138
```java
139
public class AdvancedSSLConfiguration {
140
141
public SslContextFactory.Server createSecureSSLContextFactory() {
142
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
143
144
// Keystore configuration
145
sslContextFactory.setKeyStorePath("conf/keystore.jks");
146
sslContextFactory.setKeyStorePassword("keystorepassword");
147
sslContextFactory.setKeyManagerPassword("keypassword");
148
sslContextFactory.setKeyStoreType("JKS");
149
150
// Truststore for client certificates
151
sslContextFactory.setTrustStorePath("conf/truststore.jks");
152
sslContextFactory.setTrustStorePassword("truststorepassword");
153
sslContextFactory.setTrustStoreType("JKS");
154
155
// Client certificate authentication
156
sslContextFactory.setWantClientAuth(true); // Request client cert
157
sslContextFactory.setNeedClientAuth(false); // Don't require it
158
159
// Protocol configuration - only modern TLS versions
160
sslContextFactory.setIncludeProtocols("TLSv1.2", "TLSv1.3");
161
sslContextFactory.setExcludeProtocols(
162
"SSL", "SSLv2", "SSLv3", "TLSv1", "TLSv1.1"
163
);
164
165
// Secure cipher suites only
166
sslContextFactory.setIncludeCipherSuites(
167
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
168
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
169
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
170
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
171
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
172
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
173
"TLS_AES_256_GCM_SHA384",
174
"TLS_CHACHA20_POLY1305_SHA256",
175
"TLS_AES_128_GCM_SHA256"
176
);
177
178
// Exclude weak cipher suites
179
sslContextFactory.setExcludeCipherSuites(
180
".*NULL.*", ".*RC4.*", ".*MD5.*", ".*DES.*", ".*DSS.*"
181
);
182
183
// SNI configuration
184
sslContextFactory.setSniRequired(false);
185
sslContextFactory.setSniHostCheck("example.com", "*.example.com");
186
187
// Session configuration
188
sslContextFactory.setSslSessionCacheSize(1000);
189
sslContextFactory.setSslSessionTimeout(3600); // 1 hour
190
191
// OCSP stapling
192
sslContextFactory.setEnableOCSP(true);
193
194
// Additional security settings
195
sslContextFactory.setRenegotiationAllowed(false);
196
197
return sslContextFactory;
198
}
199
200
public void setupHTTPSWithClientAuth(Server server) {
201
SslContextFactory.Server sslContextFactory = createSecureSSLContextFactory();
202
203
// Require client certificates
204
sslContextFactory.setNeedClientAuth(true);
205
206
// HTTP configuration with secure customizer
207
HttpConfiguration httpsConfig = new HttpConfiguration();
208
httpsConfig.setSecureScheme("https");
209
httpsConfig.setSecurePort(8443);
210
211
SecureRequestCustomizer secureCustomizer = new SecureRequestCustomizer();
212
secureCustomizer.setStsMaxAge(31536000); // 1 year HSTS
213
secureCustomizer.setStsIncludeSubDomains(true); // Include subdomains
214
httpsConfig.addCustomizer(secureCustomizer);
215
216
// Create HTTPS connector
217
ServerConnector httpsConnector = new ServerConnector(server,
218
new SslConnectionFactory(sslContextFactory, "http/1.1"),
219
new HttpConnectionFactory(httpsConfig));
220
httpsConnector.setPort(8443);
221
222
server.addConnector(httpsConnector);
223
}
224
}
225
```
226
227
## SecureRequestCustomizer
228
229
Customizer that adds security features to HTTPS requests.
230
231
```java { .api }
232
public class SecureRequestCustomizer implements HttpConfiguration.Customizer {
233
// HSTS (HTTP Strict Transport Security) configuration
234
public long getStsMaxAge();
235
public void setStsMaxAge(long stsMaxAge);
236
public boolean isStsIncludeSubDomains();
237
public void setStsIncludeSubDomains(boolean stsIncludeSubDomains);
238
239
// SNI (Server Name Indication) configuration
240
public boolean isSniRequired();
241
public void setSniRequired(boolean sniRequired);
242
public boolean isSniHostCheck();
243
public void setSniHostCheck(boolean sniHostCheck);
244
245
// Request customization
246
public Request customize(Request request, HttpConfiguration configuration);
247
}
248
```
249
250
## Security Headers
251
252
### Custom Security Headers Handler
253
254
```java
255
public class SecurityHeadersHandler extends Handler.Wrapper {
256
private final Map<String, String> securityHeaders;
257
258
public SecurityHeadersHandler() {
259
this.securityHeaders = new HashMap<>();
260
261
// Default security headers
262
securityHeaders.put("X-Content-Type-Options", "nosniff");
263
securityHeaders.put("X-Frame-Options", "DENY");
264
securityHeaders.put("X-XSS-Protection", "1; mode=block");
265
securityHeaders.put("Referrer-Policy", "strict-origin-when-cross-origin");
266
securityHeaders.put("Content-Security-Policy",
267
"default-src 'self'; script-src 'self' 'unsafe-inline'; " +
268
"style-src 'self' 'unsafe-inline'; img-src 'self' data:");
269
securityHeaders.put("Permissions-Policy",
270
"geolocation=(), microphone=(), camera=()");
271
}
272
273
public void setSecurityHeader(String name, String value) {
274
securityHeaders.put(name, value);
275
}
276
277
public void removeSecurityHeader(String name) {
278
securityHeaders.remove(name);
279
}
280
281
@Override
282
public boolean handle(Request request, Response response, Callback callback)
283
throws Exception {
284
285
// Add security headers to response
286
for (Map.Entry<String, String> header : securityHeaders.entrySet()) {
287
response.getHeaders().put(header.getKey(), header.getValue());
288
}
289
290
return super.handle(request, response, callback);
291
}
292
}
293
```
294
295
### HSTS Handler
296
297
```java
298
public class HSTSHandler extends Handler.Wrapper {
299
private final long maxAge;
300
private final boolean includeSubDomains;
301
private final boolean preload;
302
303
public HSTSHandler(long maxAge, boolean includeSubDomains, boolean preload) {
304
this.maxAge = maxAge;
305
this.includeSubDomains = includeSubDomains;
306
this.preload = preload;
307
}
308
309
@Override
310
public boolean handle(Request request, Response response, Callback callback)
311
throws Exception {
312
313
// Only add HSTS header for HTTPS requests
314
if (request.getConnectionMetaData().isSecure()) {
315
StringBuilder hsts = new StringBuilder();
316
hsts.append("max-age=").append(maxAge);
317
318
if (includeSubDomains) {
319
hsts.append("; includeSubDomains");
320
}
321
322
if (preload) {
323
hsts.append("; preload");
324
}
325
326
response.getHeaders().put("Strict-Transport-Security", hsts.toString());
327
}
328
329
return super.handle(request, response, callback);
330
}
331
}
332
```
333
334
## Client Certificate Authentication
335
336
```java
337
public class ClientCertificateHandler extends Handler.Abstract {
338
339
@Override
340
public boolean handle(Request request, Response response, Callback callback)
341
throws Exception {
342
343
// Check if connection is secure
344
if (!request.getConnectionMetaData().isSecure()) {
345
sendError(response, callback, 403, "HTTPS required");
346
return true;
347
}
348
349
// Get client certificates
350
X509Certificate[] clientCerts = request.getConnectionMetaData().getPeerCertificates();
351
352
if (clientCerts == null || clientCerts.length == 0) {
353
sendError(response, callback, 401, "Client certificate required");
354
return true;
355
}
356
357
// Validate client certificate
358
X509Certificate clientCert = clientCerts[0];
359
if (!isValidClientCertificate(clientCert)) {
360
sendError(response, callback, 403, "Invalid client certificate");
361
return true;
362
}
363
364
// Extract user information from certificate
365
String userDN = clientCert.getSubjectX500Principal().getName();
366
String commonName = extractCommonName(userDN);
367
368
// Set authenticated user in request
369
request.setAttribute("authenticatedUser", commonName);
370
request.setAttribute("clientCertificate", clientCert);
371
372
// Generate success response
373
response.setStatus(200);
374
response.getHeaders().put("Content-Type", "application/json");
375
376
String json = String.format(
377
"{\"authenticated\": true, \"user\": \"%s\", \"subject\": \"%s\"}",
378
commonName, userDN);
379
380
response.write(true, ByteBuffer.wrap(json.getBytes()), callback);
381
return true;
382
}
383
384
private boolean isValidClientCertificate(X509Certificate cert) {
385
try {
386
// Check certificate validity period
387
cert.checkValidity();
388
389
// Check certificate issuer (example)
390
String issuer = cert.getIssuerX500Principal().getName();
391
if (!issuer.contains("CN=My CA")) {
392
return false;
393
}
394
395
// Additional validation logic...
396
397
return true;
398
} catch (Exception e) {
399
return false;
400
}
401
}
402
403
private String extractCommonName(String dn) {
404
// Extract CN from distinguished name
405
String[] parts = dn.split(",");
406
for (String part : parts) {
407
String trimmed = part.trim();
408
if (trimmed.startsWith("CN=")) {
409
return trimmed.substring(3);
410
}
411
}
412
return "Unknown";
413
}
414
415
private void sendError(Response response, Callback callback, int status, String message) {
416
response.setStatus(status);
417
response.getHeaders().put("Content-Type", "text/plain");
418
response.write(true, ByteBuffer.wrap(message.getBytes()), callback);
419
}
420
}
421
```
422
423
## HTTPS Redirect Handler
424
425
```java
426
public class HTTPSRedirectHandler extends Handler.Abstract {
427
private final int httpsPort;
428
429
public HTTPSRedirectHandler(int httpsPort) {
430
this.httpsPort = httpsPort;
431
}
432
433
@Override
434
public boolean handle(Request request, Response response, Callback callback)
435
throws Exception {
436
437
// Check if request is already HTTPS
438
if (request.getConnectionMetaData().isSecure()) {
439
return false; // Let next handler process
440
}
441
442
// Build HTTPS URL
443
String scheme = "https";
444
String host = request.getHeaders().get("Host");
445
if (host == null) {
446
host = "localhost";
447
}
448
449
// Remove port from host if present
450
if (host.contains(":")) {
451
host = host.substring(0, host.indexOf(":"));
452
}
453
454
String httpsUrl = scheme + "://" + host +
455
(httpsPort != 443 ? ":" + httpsPort : "") +
456
request.getHttpURI().getPathQuery();
457
458
// Send redirect response
459
response.setStatus(301); // Permanent redirect
460
response.getHeaders().put("Location", httpsUrl);
461
response.getHeaders().put("Connection", "close");
462
463
callback.succeeded();
464
return true;
465
}
466
}
467
```
468
469
## Complete Secure Server Setup
470
471
```java
472
public class SecureServerSetup {
473
474
public Server createSecureServer() throws Exception {
475
Server server = new Server();
476
477
// HTTP connector (redirects to HTTPS)
478
ServerConnector httpConnector = new ServerConnector(server);
479
httpConnector.setPort(8080);
480
server.addConnector(httpConnector);
481
482
// HTTPS connector
483
SslContextFactory.Server sslContextFactory = createSslContextFactory();
484
HttpConfiguration httpsConfig = createHttpsConfiguration();
485
486
ServerConnector httpsConnector = new ServerConnector(server,
487
new SslConnectionFactory(sslContextFactory, "http/1.1"),
488
new HttpConnectionFactory(httpsConfig));
489
httpsConnector.setPort(8443);
490
server.addConnector(httpsConnector);
491
492
// Create handler chain with security
493
Handler securityChain = createSecurityHandlerChain();
494
server.setHandler(securityChain);
495
496
return server;
497
}
498
499
private SslContextFactory.Server createSslContextFactory() {
500
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
501
502
// SSL configuration
503
sslContextFactory.setKeyStorePath("conf/keystore.jks");
504
sslContextFactory.setKeyStorePassword("password");
505
sslContextFactory.setTrustStorePath("conf/truststore.jks");
506
sslContextFactory.setTrustStorePassword("password");
507
508
// Security settings
509
sslContextFactory.setIncludeProtocols("TLSv1.2", "TLSv1.3");
510
sslContextFactory.setExcludeProtocols("SSLv3", "TLSv1", "TLSv1.1");
511
sslContextFactory.setIncludeCipherSuites(
512
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
513
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
514
);
515
516
// Client certificate support
517
sslContextFactory.setWantClientAuth(true);
518
519
return sslContextFactory;
520
}
521
522
private HttpConfiguration createHttpsConfiguration() {
523
HttpConfiguration httpsConfig = new HttpConfiguration();
524
httpsConfig.setSecureScheme("https");
525
httpsConfig.setSecurePort(8443);
526
527
// Add secure request customizer
528
SecureRequestCustomizer secureCustomizer = new SecureRequestCustomizer();
529
secureCustomizer.setStsMaxAge(31536000); // 1 year HSTS
530
secureCustomizer.setStsIncludeSubDomains(true); // Include subdomains
531
httpsConfig.addCustomizer(secureCustomizer);
532
533
return httpsConfig;
534
}
535
536
private Handler createSecurityHandlerChain() {
537
// HTTPS redirect handler
538
HTTPSRedirectHandler httpsRedirect = new HTTPSRedirectHandler(8443);
539
540
// Security headers handler
541
SecurityHeadersHandler securityHeaders = new SecurityHeadersHandler();
542
543
// HSTS handler
544
HSTSHandler hstsHandler = new HSTSHandler(31536000, true, false);
545
546
// Client certificate authentication (optional)
547
ClientCertificateHandler clientCertAuth = new ClientCertificateHandler();
548
549
// Application handler
550
Handler applicationHandler = new MyApplicationHandler();
551
552
// Chain handlers together
553
httpsRedirect.setHandler(securityHeaders);
554
securityHeaders.setHandler(hstsHandler);
555
hstsHandler.setHandler(clientCertAuth);
556
clientCertAuth.setHandler(applicationHandler);
557
558
return httpsRedirect;
559
}
560
}
561
```
562
563
## SSL Debugging and Monitoring
564
565
```java
566
public class SSLMonitoringHandler extends Handler.Wrapper {
567
568
@Override
569
public boolean handle(Request request, Response response, Callback callback)
570
throws Exception {
571
572
ConnectionMetaData connMeta = request.getConnectionMetaData();
573
574
if (connMeta.isSecure()) {
575
logSSLInfo(request);
576
}
577
578
return super.handle(request, response, callback);
579
}
580
581
private void logSSLInfo(Request request) {
582
ConnectionMetaData connMeta = request.getConnectionMetaData();
583
584
System.out.println("SSL Connection Info:");
585
System.out.println(" Protocol: " + connMeta.getProtocol());
586
System.out.println(" Secure: " + connMeta.isSecure());
587
588
// Client certificate info
589
X509Certificate[] clientCerts = connMeta.getPeerCertificates();
590
if (clientCerts != null && clientCerts.length > 0) {
591
X509Certificate clientCert = clientCerts[0];
592
System.out.println(" Client Certificate:");
593
System.out.println(" Subject: " + clientCert.getSubjectX500Principal().getName());
594
System.out.println(" Issuer: " + clientCert.getIssuerX500Principal().getName());
595
System.out.println(" Serial: " + clientCert.getSerialNumber());
596
} else {
597
System.out.println(" No client certificate");
598
}
599
}
600
}
601
```