如何忽略Feign中的SSL证书信任错误?

Bee*_*Bee 7 ssl netflix-feign feign

我怎样才能curl -kfeign客户端实现?

我知道我能做到这一点.只是想知道是否有办法忽略或禁用.

new Client.Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier)
Run Code Online (Sandbox Code Playgroud)

Dan*_*ith 17

放弃

实际上你不应该出于很多原因这样做.解决SSL问题的最简单方法是实际遵循SSL最佳实践并使用有效证书.有一些优秀的在线项目,如https://letsencrypt.org/,如果主机可公开访问(如果它有一个可以验证的真实主机名),它甚至可以让你免费获得很好的安全性.

自行承担使用风险.请确认你理解你违反了很多最好的做法,并且只有在你理解的情况下才能使用它.

如果您使用此示例代码导致某些类型的主要问题,则您需要承担责任.

真正的谈话

处理我想从spring-boot应用程序调用的内部(公共不可访问)服务时遇到了同样的问题,我使用以下代码解决了它.

简要概述

很多人会告诉你,你可以接受所有证书,硬编码你的特定证书,或其他东西.实际上,您可以通过代码路径仅允许某些可信主机,这就是我在这里尝试获得额外的安全层.

在此示例代码中,您可以将多个主机传递给类,并且它应该允许仅向那些主机发出无效证书的请求,而其他所有主机都将通过正常的命令链.

这不是真正的生产级代码,但希望你能从中获得一些用处.

足够的讲课,以下内容可能对您最感兴趣.

代码

这用于Java 8和spring-boot.

组态

@Configuration
public class FeignClientConfiguration {
    @Bean
    public Client client() throws NoSuchAlgorithmException, KeyManagementException {
        return new Client.Default(new NaiveSSLSocketFactory("your.host.here"), 
                                  new NaiveHostnameVerifier("your.host.here"));
    }
}
Run Code Online (Sandbox Code Playgroud)

NaiveHostnameVerifier

public class NaiveHostnameVerifier implements HostnameVerifier {
    private final Set<String> naivelyTrustedHostnames;
    private final HostnameVerifier hostnameVerifier =
        HttpsURLConnection.getDefaultHostnameVerifier();

    public NaiveHostnameVerifier(String ... naivelyTrustedHostnames) {
        this.naivelyTrustedHostnames =
                Collections.unmodifiableSet(new HashSet<>(Arrays.asList(naivelyTrustedHostnames)));
    }

    @Override
    public boolean verify(String hostname, SSLSession session) {
        return naivelyTrustedHostnames.contains(hostname) ||
                hostnameVerifier.verify(hostname, session);
    }
}
Run Code Online (Sandbox Code Playgroud)

NaiveSSLSocketFactory

public class NaiveSSLSocketFactory extends SSLSocketFactory {
    private final SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    private final SSLContext alwaysAllowSslContext;
    private final Set<String> naivelyTrustedHostnames;

    public NaiveSSLSocketFactory(String ... naivelyTrustedHostnames) throws NoSuchAlgorithmException, KeyManagementException {
        this.naivelyTrustedHostnames =
                Collections.unmodifiableSet(new HashSet<>(Arrays.asList(naivelyTrustedHostnames)));
        alwaysAllowSslContext = SSLContext.getInstance("TLS");
        TrustManager tm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        alwaysAllowSslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return sslSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return sslSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return (naivelyTrustedHostnames.contains(host)) ?
                alwaysAllowSslContext.getSocketFactory().createSocket(socket, host, port, autoClose) :
                sslSocketFactory.createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return (naivelyTrustedHostnames.contains(host)) ?
                alwaysAllowSslContext.getSocketFactory().createSocket(host, port) :
                sslSocketFactory.createSocket(host, port);
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException, UnknownHostException {
        return (naivelyTrustedHostnames.contains(host)) ?
                alwaysAllowSslContext.getSocketFactory().createSocket(host, port, localAddress, localPort) :
                sslSocketFactory.createSocket(host, port, localAddress, localPort);
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return (naivelyTrustedHostnames.contains(host.getHostName())) ?
                alwaysAllowSslContext.getSocketFactory().createSocket(host, port) :
                sslSocketFactory.createSocket(host, port);
    }

    @Override
    public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException {
        return (naivelyTrustedHostnames.contains(host.getHostName())) ?
                alwaysAllowSslContext.getSocketFactory().createSocket(host, port, localHost, localPort) :
                sslSocketFactory.createSocket(host, port, localHost, localPort);
    }
}
Run Code Online (Sandbox Code Playgroud)

参考

我从这个答案中大量借用:

使用HttpClient通过HTTPS信任所有证书


Dir*_*irk 14

使用Spring Cloud Netflix >= 1.4.4.RELEASE 时,您还可以执行以下操作:

添加okhttp客户端maven依赖:

    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-okhttp</artifactId>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

并添加以下属性:

feign.httpclient.disableSslValidation=true
feign.httpclient.enabled=false
feign.okhttp.enabled=true
Run Code Online (Sandbox Code Playgroud)

参考:https : //github.com/spring-cloud/spring-cloud-netflix/issues/2729

  • disableSslValidation 也适用于 apache httpclient。请参阅下面我的回答。 (2认同)

Ber*_*olt 10

使用当前版本的 spring-cloud-starter-openfeign 抑制主机名验证的工作原理如下。

使用 apache httpclient 时:

在 application.yml 中设置disable-ssl-validation属性

feign.httpclient.disable-ssl-validation: true
Run Code Online (Sandbox Code Playgroud)

在 pom.xml 中添加 feign-httpclient 依赖项。

<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-httpclient</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

如果您更喜欢 okhttp,则必须使用另一个应用程序属性启用 okhttp 并添加 feign-okhttp 依赖项:

feign.httpclient.disableSslValidation=true
feign.httpclient.enabled=false
feign.okhttp.enabled=true

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

对于httpclient5(hc5),遗憾的是属性disable-ssl-validation并没有关闭主机名验证(还?),这是票证: https: //github.com/spring-cloud/spring-cloud-openfeign/issues/625

用于启用 hc5 的应用程序属性。

feign.httpclient.disableSslValidation=true
feign.httpclient.hc5.enabled=true
Run Code Online (Sandbox Code Playgroud)

添加Maven依赖

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-hc5</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

注意:对我来说最棘手的部分是我错过了添加 feign-httpclient 作为依赖项。在这种情况下,使用启用了主机名验证的默认 feign 客户端。


wan*_*ana 6

feign.httpclient.disableSslValidation = true 对我不起作用。

通过以下代码在配置中创建客户端bean:

import feign.Client;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContexts;
import org.springframework.context.annotation.Bean;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

public class ClientConfiguration {

    @Bean
    public Client feignClient() {
        return new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
    }

    private SSLSocketFactory getSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
            return sslContext.getSocketFactory();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

pom.xml 可能需要添加依赖项:

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.8</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)


era*_*del 5

通过伪装配置覆盖

@Bean
public Client feignClient()
{
    Client trustSSLSockets = new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
    return trustSSLSockets;
}


private SSLSocketFactory getSSLSocketFactory() {
    try {
        TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        };

        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
        return sslContext.getSocketFactory();
    } catch (Exception exception) {
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)