在Apache Kafka Java客户端中禁用SSL证书验证是否可能?

8
如果我有一个自签名证书,作为一名好公民,我会将其导入我的密钥库,并使用“ssl.truststore.location”和“ssl.truststore.type”配置Kafka客户端以便使用它。
如果证书的主题中的通用名称与呈现它的主机地址不同,则可以通过“ssl.endpoint.identification.algorithm”关闭端点验证。
如果我想完全跳过SSL验证,而不仅仅是为了主机名,这样我就不再需要复制证书了,类似于curl中的“-k”或“--insecure”设置,是否可以使用Kafka的默认Java客户端来实现?

我发现在Java中,https://dev59.com/x7Hma4cB1Zd3GeqPN5h8#54517407 对于同样的问题非常有用。 - Shivam Puri
@ShivamPuri 是的,在Java中使用noop TrustManager可以完成任务,我正在寻找类似的解决方案。但是Kafka客户端会自行初始化,并且据我所知,我只能使用其公开的设置来配置它,因此我找不到任何方法来实现这一点。 - Dth
1
如果您同时跳过认证和主机名验证,那么使用 PLAINTEXT 而非 SSL 似乎更合适。 - Mickael Maison
8
@MickaelMaison,SSL没有身份验证仍然有用。即使在连接的两端都没有进行身份验证,加密的网络流量仍然是一种好处。 - jeremysprofile
2个回答

6

有一种方法可以实现它,但并不那么简单。

想法是实现接口org.apache.kafka.common.security.auth.SslEngineFactory,该接口将忽略证书验证。当您将其用作客户端时,应足以仅实现createClientSslEngine方法,类似于以下方式:

import org.apache.kafka.common.security.auth.SslEngineFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;

public class InsecureSslEngineFactory implements SslEngineFactory {

    private final TrustManager INSECURE_TRUST_MANAGER = new X509TrustManager() {

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) {
            // empty
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            // empty
        }
    };

    @Override
    public SSLEngine createClientSslEngine(String peerHost, int peerPort, String endpointIdentification) {
        TrustManager[] trustManagers = new TrustManager[]{ INSECURE_TRUST_MANAGER };
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagers, new SecureRandom());
            SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort);
            sslEngine.setUseClientMode(true);
            return sslEngine;
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public SSLEngine createServerSslEngine(String peerHost, int peerPort) {
        return null;
    }

    @Override
    public boolean shouldBeRebuilt(Map<String, Object> nextConfigs) {
        return false;
    }

    @Override
    public Set<String> reconfigurableConfigs() {
        return null;
    }

    @Override
    public KeyStore keystore() {
        return null;
    }

    @Override
    public KeyStore truststore() {
        return null;
    }

    @Override
    public void close() {

    }

    @Override
    public void configure(Map<String, ?> configs) {

    }
}

完成这个类后,您只需将其配置为kafka(生产者或消费者)属性中的SSL_ENGINE_FACTORY_CLASS即可:
props.put(SslConfigs.SSL_ENGINE_FACTORY_CLASS, InsecureSslEngineFactory.class);

或者,如果您不想使用常量:

props.put("ssl.engine.factory.class", InsecureSslEngineFactory.class);

请确保不要在生产环境中使用此设置!


1
希望能添加导入部分。 - Vladyslav Nikolaiev
1
导入部分已添加。 - martinnemec3

1

src/main/resources/application.yml

#Server host name verification is disabled by setting ssl.endpoint.identification.algorithm to an empty string
spring.kafka.properties.ssl.endpoint.identification.algorithm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接