有没有办法连接ldaps并忽略java中的证书?

问题描述 投票:0回答:5

我在 tomcat 上有一个带有 ldap 的 java 应用程序,我可以毫无问题地进行身份验证。现在,我的公司要在ldap上插入ssl层,所以我需要使用ldaps。有什么建议可以忽略来自 ldaps 服务器的证书和信任证书吗?

这是我适用于 ldap 的代码

final String ldapAdServer = "ldap://my_ldap_url:3268";
final String ldapSearchBase = "Ldap_search_base";

//need a default user to be able to do query on AD
final String ldapUsername = "username_path_AD";
final String ldapPassword = "password_path_AD";


Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
if(ldapUsername != null) {
    env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if(ldapPassword != null) {
    env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapAdServer);

//ensures that objectSID attribute values
//will be returned as a byte[] instead of a String
env.put("java.naming.ldap.attributes.binary", "objectSID");

LdapContext ctx = new InitialLdapContext(env,null);

return ctx;

现在,我尝试创建此类来信任所有证书:

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


public class SSLFix {
 
 public static void execute(){
  TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
           return null;
          }
          @Override
          public void checkClientTrusted(X509Certificate[] arg0, String arg1)
           throws CertificateException {}
 
          @Override
          public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {}

          }
     };

  SSLContext sc=null;
  try {
   sc = SSLContext.getInstance("SSL");
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
  try {
   sc.init(null, trustAllCerts, new java.security.SecureRandom());
  } catch (KeyManagementException e) {
   e.printStackTrace();
  }
  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

  // Create all-trusting host name verifier
  HostnameVerifier validHosts = new HostnameVerifier() {
  @Override
  public boolean verify(String arg0, SSLSession arg1) {
   return true;
  }
  };
  // All hosts will be valid
  HttpsURLConnection.setDefaultHostnameVerifier(validHosts);
 }

}

所以我决定用这个来改变我以前的 LDAP 代码:

public LdapContext getLDAPContext() throws NamingException
{
    SSLFix.execute();
    
    
    final String ldapAdServer = "ldaps://my_ldap_url:3269";
    final String ldapSearchBase = "ldap_search_base";
    
//need a default user to be able to do query on AD
    final String ldapUsername = "username_path_AD";
    final String ldapPassword = "password_path_AD";
    
    
    Hashtable<String, Object> env = new Hashtable<String, Object>();
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    if(ldapUsername != null) {
        env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
    }
    if(ldapPassword != null) {
        env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
    }
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ldapAdServer);

    //ensures that objectSID attribute values
    //will be returned as a byte[] instead of a String
    env.put("java.naming.ldap.attributes.binary", "objectSID");
    
    LdapContext ctx = new InitialLdapContext(env,null);
    
    return ctx;
}

但是当我执行 ldaps 的控制时,我收到此错误:

javax.naming.CommunicationException:简单绑定失败:[根异常是 javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到有效的达到请求目标的认证路径]

java ldap ssl-certificate trust
5个回答
4
投票

您必须将“LDAP-CA 证书”导入您的 Java 虚拟机。
为此,您可以运行:
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias ldap-CA -import -file ldap-ca-crt.pem

如果你的证书是好的。您的所有客户端(网络浏览器或移动 SO)在使用您的应用程序时都不会出现问题。

不要忘记导入中间证书或链式证书。(这些证书通常与 LDAP-CA 证书一起提供)


0
投票

您可以创建自定义 X509TrustManager 或 SSLSocketFactory。

https://stackoverflow.com/a/4615497/88122

找到了两者的示例

0
投票

感谢大家的回复。我决定创建 X509TrustManager 和 SSLSocketFactory,因此允许所有证书。我用这种方式解决了我的问题


0
投票

我不知道您的环境,但是您能否将发布LDAP证书的CA证书添加到您系统的可信CA中?

通过这种方式,您可以增强应用程序的安全性,否则使用 LDAP 几乎毫无用处。

我假设域控制器安装了一个CA服务器并且LDAP的证书是由它发布的。下载此证书并将其添加到您的环境中。

如果应用程序安装在域的计算机上,您可以共享 CA 证书并抛出组策略规则。您可以查看Microsoft 文档。域中的每个证书都必须由受信任的 CA 发布。

如果您无法接受此证书,请使用此answer中的选项 2。


0
投票

将 CA 添加到证书存储中的问题是显而易见的。 1)它会起作用。 5年,也许8年。然后证书突然过期,一切,我指出——一切——都会消亡。你将会遭受全公司范围的灾难。

  1. 这没有任何意义。所有系统必须做的就像 ssh - 导入证书并报告其更改。

  2. 禁用证书验证的 LDAPS 比不加密的 LDAP 更好。

在某些情况下我们需要证书验证。例如,如果我们在数据传输中使用公共互联网,或者当我们没有好的方法来信任直接证书传递时。但是,这些并不常见。

问题是因为JAVA无法禁用证书验证,所以很多情况下我们不能使用LDAPS而必须使用不那么安全的LDAP。由于整个公司崩溃的风险太高,无法在受保护的网络内使用证书验证。所以我们需要一种方法来阻止这种检查,至少在必要时是这样。当它在两个不同的团体之间时这是可以的,但在内联网中绝对是糟糕的想法 - 因为从长远来看它太危险了。

© www.soinside.com 2019 - 2024. All rights reserved.