Java 7u25使用JNDI连接LDAPS无法采用TLS 1.2,默认走TLSv1如何解决?
问题根因
-Dhttps.protocols参数仅对JDK内置的HttpsURLConnection类生效,而JNDI LDAP的SSL连接逻辑是独立实现的,不会读取该参数,同时你使用的Java 7u25版本也不支持jdk.tls.client.protocols系统参数,因此默认始终使用TLSv1发起握手。
解决方案
以下是兼容性最高的实现方案,无需额外引入第三方依赖:
步骤1:实现自定义TLSv1.2专用SSLSocketFactory
自定义套接字工厂会在创建SSL连接时强制指定启用TLSv1.2协议:
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; public class TLS12SocketFactory extends SSLSocketFactory { private final SSLSocketFactory delegate; public TLS12SocketFactory() { this.delegate = (SSLSocketFactory) SSLSocketFactory.getDefault(); } // JNDI会通过反射调用该静态方法获取工厂实例,必须保留 public static SSLSocketFactory getDefault() { return new TLS12SocketFactory(); } private Socket wrapTLS12Socket(Socket socket) { if (socket instanceof SSLSocket) { ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.2"}); } return socket; } @Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return wrapTLS12Socket(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException { return wrapTLS12Socket(delegate.createSocket(host, port)); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { return wrapTLS12Socket(delegate.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return wrapTLS12Socket(delegate.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return wrapTLS12Socket(delegate.createSocket(address, port, localAddress, localPort)); } }
步骤2:修改LDAP上下文配置
在你原有的LDAP配置中新增一行,指定使用自定义的套接字工厂:
// 原有配置保持不变,新增以下配置项 LDAPOptions.put("java.naming.ldap.factory.socket", TLS12SocketFactory.class.getName());
修改后的核心配置示例:
LDAPOptions.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); LDAPOptions.put(Context.SECURITY_PROTOCOL, "ssl"); // 新增自定义套接字工厂配置 LDAPOptions.put("java.naming.ldap.factory.socket", TLS12SocketFactory.class.getName());
可选轻量方案
如果你使用的是Oracle官方JDK 7u25,也可以先尝试直接添加以下配置项,无需自定义工厂,配置不生效再用上述方案即可:
LDAPOptions.put("com.sun.jndi.ldap.tls.protocols", "TLSv1.2");
验证
保留-Djavax.net.debug=ssl启动参数,重新运行程序后查看SSL日志,会输出*** ClientHello, TLSv1.2,即可确认TLS版本符合要求。
内容的提问来源于stack exchange,提问作者TheCrunchyFerrett
相关产品推荐
相关产品推荐

