Jetty 升级到 9.4.19.v20190610 后,传入的客户端请求中未出现 X509 证书
X509 Certificates are not coming in incoming client request after Jetty Upgrade to 9.4.19.v20190610
Jetty 升级到
后,我没有在传入的客户端请求中获得 X509 证书
9.4.19.v20190610
certifcates = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
此处证书为空。虽然他们是 Jetty 版本
9.4.11.v20180605
我的客户端程序:
private static String loginWithCertificate(String aEndPointURL) {
String line = "";
try {
final String CERT_ALIAS = "employee1";
String CERT_PASSWORD = "changeit";
KeyStore identityKeyStore = KeyStore.getInstance("jks");
FileInputStream identityKeyStoreFile = new FileInputStream(new File(ResourceUtils.getFile("./stores/client1.jks").getAbsolutePath()));
identityKeyStore.load(identityKeyStoreFile, CERT_PASSWORD.toCharArray());
KeyStore trustKeyStore = KeyStore.getInstance("jks");
FileInputStream trustKeyStoreFile = new FileInputStream(new File(ResourceUtils.getFile("./stores/truststore1.jks").getAbsolutePath()));
trustKeyStore.load(trustKeyStoreFile, CERT_PASSWORD.toCharArray());
SSLContext sslContext = SSLContexts.custom()
// load identity keystore
.loadKeyMaterial(identityKeyStore, CERT_PASSWORD.toCharArray(), new PrivateKeyStrategy() {
@Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
return CERT_ALIAS;
}
})
// load trust keystore
.loadTrustMaterial(trustKeyStore, null).build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }, null, SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
HttpPost req = new HttpPost(aEndPointURL);
StringEntity entity = new StringEntity(
"{\"ipAddress\" : \"172.20.186.74\", \"port\" : 1363, \"protocol\" : \"tls1.2\"}");
req.setHeader("Content-type", "application/json");
req.setHeader("X-XSRF-TOKEN", "Y2hlY2tpdA==");
req.setHeader("CertificateAuthentication", "true");
req.setEntity(entity);
HttpResponse response = client.execute(req);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (Exception ex) {
System.out.println("Exception : " + ex);
ex.printStackTrace();
}
return line;
}
我在服务器上的 SSL 连接器:
public EmbeddedServletContainerFactory customizeJetty() {
JettyEmbeddedServletContainerFactory container = new JettyEmbeddedServletContainerFactory();
container.addServerCustomizers(new JettyServerCustomizer() {
@Override
public void customize(Server server) {
// HTTP
try (ServerConnector connector = new ServerConnector(server);) {
validateHttpPort(httpPort, securedPort);
connector.setPort(Integer.parseInt(httpPort));
// HTTPS
SslContextFactory sslContextFactory = new SslContextFactory();
URL urlKeyStore = null;
Path keyStoreFilePath = null;
File keyStoreFile = null;
// Appscan Vulnerability - Should not use Hardcoded paths using File Separator.
// We should use Path API to read the files.
keyStoreFilePath = Paths.get("WebServices", "src", "main", "resources");
keyStoreFile = Paths.get(keyStoreFilePath.toString(), keyStoreName).toFile();
if (!keyStoreFile.exists()) {
keyStoreFilePath = fetchPathForKeyStore();
keyStoreFile = keyStoreFilePath.toFile();
}
urlKeyStore = fetchKeyStoreUrl(keyStoreFile);
validateUrlKeyStore(urlKeyStore);
sslContextFactory.setKeyStoreResource(Resource.newResource(urlKeyStore));
// Getting Credentials from hidden file
String encodedProperty = MFTUtils.fetchCredentialForKeyStore();
validateEncodedProperty(encodedProperty);
StringTokenizer tokenizer = new StringTokenizer(encodedProperty,
MFTConstants.HTTP_CREDENTIAL_DELIMITER); // constant
validateTokens(tokenizer);
String encodedCredential = tokenizer.nextToken();
String credentialKey = tokenizer.nextToken();
String credential = AESEncryptionDecryption.decrypt(encodedCredential, credentialKey);
// null checking credentials
validateCredential(credential, credentialKey);
sslContextFactory.setKeyStorePassword(credential);
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
sslContextFactory.setExcludeProtocols("");
HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
if (System.getProperty(MFTConstants.SERVER_SSL_ENABLED).equalsIgnoreCase(MFTConstants.TRUE)) {
UtilLogger.debug(logger, "HTTPS is enabled.");
try (ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, MFTConstants.HTTP_PROTOCOL),
new HttpConnectionFactory(https));) {
sslConnector.setPort(Integer.parseInt(securedPort));
server.setConnectors(new Connector[] { connector, sslConnector });
}
} else {
UtilLogger.debug(logger, "HTTPS is disabled. Application will run over HTTP only.");
try (ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, MFTConstants.HTTP_PROTOCOL));) {
server.setConnectors(new Connector[] { connector });
}
}
}
}
我正在尝试使用自签名证书。
更新
我正在使用 jks 密钥库。即没有密钥的证书。
:
任何帮助将不胜感激。
仔细查看服务器端 SslContextFactory 的使用情况,着眼于您实际使用的内容(剥离以仅显示 SslContextFactory 的使用情况)
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreResource(Resource.newResource(urlKeyStore));
sslContextFactory.setKeyStorePassword(credential);
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
sslContextFactory.setExcludeProtocols("");
有几件事很突出。
首先,既然你是服务器,就应该使用服务器版本...
SslContextFactory sslContextFactory = new SslContextFactory.Server();
接下来,您对 .setExcludedCipherSuites()
的使用不完整并引入了漏洞。
删除(或注释掉)整行。
使用 SslContextFactory 为您提供的默认值。
使用该行,可以使用 TLS/SSL.
的无证书和无加密配置
此外,您对 setExcludedProtocols("")
的使用很糟糕。它正在设置要排除的单个空白协议。这很糟糕,因为您将自己暴露在各种 SSL 漏洞中(更不用说 TLS 漏洞了)
也删除(或注释掉)整行。
使用 SslContextFactory 为您提供的默认值。
使用该行,可以对 TLS/SSL.
使用无协议(这意味着无加密)配置
以上2种配置产生的警告日志数不胜数,你应该努力拥有一个没有警告的配置。
对于上述两个问题,您可能会从连接中使用的密码套件的名称中了解到一些信息。
String cipherSuiteName =
(String) HttpServletRequest.getAttribute("javax.servlet.request.cipher_suite");
您甚至可以获得连接中使用的javax.net.ssl.SSLSession
。
SslSession sslSession =
(SslSession) HttpServletRequest.getAttribute(
"org.eclipse.jetty.servlet.request.ssl_session");
System.out.println("protocol is " + sslSession.getProtocol());
System.out.println("cipher suite is " + sslSession.getCipherSuite());
System.out.println("peer certs is " + sslSession.getPeerCertificates());
最后,您的代码没有任何迹象表明您甚至想要来自该配置的客户端证书。
你有没有忘记其中一个...
sslContextFactory.setNeedClientAuth(true);
sslContextFactory.setWantClientAuth(true);
或者您真的不需要客户端证书?
Jetty 升级到
后,我没有在传入的客户端请求中获得 X509 证书9.4.19.v20190610
certifcates = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
此处证书为空。虽然他们是 Jetty 版本
9.4.11.v20180605
我的客户端程序:
private static String loginWithCertificate(String aEndPointURL) {
String line = "";
try {
final String CERT_ALIAS = "employee1";
String CERT_PASSWORD = "changeit";
KeyStore identityKeyStore = KeyStore.getInstance("jks");
FileInputStream identityKeyStoreFile = new FileInputStream(new File(ResourceUtils.getFile("./stores/client1.jks").getAbsolutePath()));
identityKeyStore.load(identityKeyStoreFile, CERT_PASSWORD.toCharArray());
KeyStore trustKeyStore = KeyStore.getInstance("jks");
FileInputStream trustKeyStoreFile = new FileInputStream(new File(ResourceUtils.getFile("./stores/truststore1.jks").getAbsolutePath()));
trustKeyStore.load(trustKeyStoreFile, CERT_PASSWORD.toCharArray());
SSLContext sslContext = SSLContexts.custom()
// load identity keystore
.loadKeyMaterial(identityKeyStore, CERT_PASSWORD.toCharArray(), new PrivateKeyStrategy() {
@Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
return CERT_ALIAS;
}
})
// load trust keystore
.loadTrustMaterial(trustKeyStore, null).build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }, null, SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
HttpPost req = new HttpPost(aEndPointURL);
StringEntity entity = new StringEntity(
"{\"ipAddress\" : \"172.20.186.74\", \"port\" : 1363, \"protocol\" : \"tls1.2\"}");
req.setHeader("Content-type", "application/json");
req.setHeader("X-XSRF-TOKEN", "Y2hlY2tpdA==");
req.setHeader("CertificateAuthentication", "true");
req.setEntity(entity);
HttpResponse response = client.execute(req);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (Exception ex) {
System.out.println("Exception : " + ex);
ex.printStackTrace();
}
return line;
}
我在服务器上的 SSL 连接器:
public EmbeddedServletContainerFactory customizeJetty() {
JettyEmbeddedServletContainerFactory container = new JettyEmbeddedServletContainerFactory();
container.addServerCustomizers(new JettyServerCustomizer() {
@Override
public void customize(Server server) {
// HTTP
try (ServerConnector connector = new ServerConnector(server);) {
validateHttpPort(httpPort, securedPort);
connector.setPort(Integer.parseInt(httpPort));
// HTTPS
SslContextFactory sslContextFactory = new SslContextFactory();
URL urlKeyStore = null;
Path keyStoreFilePath = null;
File keyStoreFile = null;
// Appscan Vulnerability - Should not use Hardcoded paths using File Separator.
// We should use Path API to read the files.
keyStoreFilePath = Paths.get("WebServices", "src", "main", "resources");
keyStoreFile = Paths.get(keyStoreFilePath.toString(), keyStoreName).toFile();
if (!keyStoreFile.exists()) {
keyStoreFilePath = fetchPathForKeyStore();
keyStoreFile = keyStoreFilePath.toFile();
}
urlKeyStore = fetchKeyStoreUrl(keyStoreFile);
validateUrlKeyStore(urlKeyStore);
sslContextFactory.setKeyStoreResource(Resource.newResource(urlKeyStore));
// Getting Credentials from hidden file
String encodedProperty = MFTUtils.fetchCredentialForKeyStore();
validateEncodedProperty(encodedProperty);
StringTokenizer tokenizer = new StringTokenizer(encodedProperty,
MFTConstants.HTTP_CREDENTIAL_DELIMITER); // constant
validateTokens(tokenizer);
String encodedCredential = tokenizer.nextToken();
String credentialKey = tokenizer.nextToken();
String credential = AESEncryptionDecryption.decrypt(encodedCredential, credentialKey);
// null checking credentials
validateCredential(credential, credentialKey);
sslContextFactory.setKeyStorePassword(credential);
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
sslContextFactory.setExcludeProtocols("");
HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
if (System.getProperty(MFTConstants.SERVER_SSL_ENABLED).equalsIgnoreCase(MFTConstants.TRUE)) {
UtilLogger.debug(logger, "HTTPS is enabled.");
try (ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, MFTConstants.HTTP_PROTOCOL),
new HttpConnectionFactory(https));) {
sslConnector.setPort(Integer.parseInt(securedPort));
server.setConnectors(new Connector[] { connector, sslConnector });
}
} else {
UtilLogger.debug(logger, "HTTPS is disabled. Application will run over HTTP only.");
try (ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, MFTConstants.HTTP_PROTOCOL));) {
server.setConnectors(new Connector[] { connector });
}
}
}
}
我正在尝试使用自签名证书。
更新 我正在使用 jks 密钥库。即没有密钥的证书。
:
任何帮助将不胜感激。
仔细查看服务器端 SslContextFactory 的使用情况,着眼于您实际使用的内容(剥离以仅显示 SslContextFactory 的使用情况)
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreResource(Resource.newResource(urlKeyStore));
sslContextFactory.setKeyStorePassword(credential);
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
sslContextFactory.setExcludeProtocols("");
有几件事很突出。
首先,既然你是服务器,就应该使用服务器版本...
SslContextFactory sslContextFactory = new SslContextFactory.Server();
接下来,您对 .setExcludedCipherSuites()
的使用不完整并引入了漏洞。
删除(或注释掉)整行。
使用 SslContextFactory 为您提供的默认值。
使用该行,可以使用 TLS/SSL.
此外,您对 setExcludedProtocols("")
的使用很糟糕。它正在设置要排除的单个空白协议。这很糟糕,因为您将自己暴露在各种 SSL 漏洞中(更不用说 TLS 漏洞了)
也删除(或注释掉)整行。
使用 SslContextFactory 为您提供的默认值。
使用该行,可以对 TLS/SSL.
以上2种配置产生的警告日志数不胜数,你应该努力拥有一个没有警告的配置。
对于上述两个问题,您可能会从连接中使用的密码套件的名称中了解到一些信息。
String cipherSuiteName =
(String) HttpServletRequest.getAttribute("javax.servlet.request.cipher_suite");
您甚至可以获得连接中使用的javax.net.ssl.SSLSession
。
SslSession sslSession =
(SslSession) HttpServletRequest.getAttribute(
"org.eclipse.jetty.servlet.request.ssl_session");
System.out.println("protocol is " + sslSession.getProtocol());
System.out.println("cipher suite is " + sslSession.getCipherSuite());
System.out.println("peer certs is " + sslSession.getPeerCertificates());
最后,您的代码没有任何迹象表明您甚至想要来自该配置的客户端证书。
你有没有忘记其中一个...
sslContextFactory.setNeedClientAuth(true);
sslContextFactory.setWantClientAuth(true);
或者您真的不需要客户端证书?