【问题标题】:SSLHandshakeException: Certificate Unknown (Java Spring Boot & Android)SSLHandshakeException:证书未知(Java Spring Boot 和 Android)
【发布时间】:2020-05-21 22:23:03
【问题描述】:

我有一个使用 HTTPS 协议在本地运行的带有自签名证书的 Spring Boot API。 显然,当我从浏览器发送GET请求时,我在服务器端收到io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown错误,这是正常的,因为自签名不被浏览器信任。邮递员适用于 GETPOST

但是,我想从 Android 客户端向 Spring API 发送 GET 请求,但是,即使我使用了允许所有 SSL 流量的函数(是的,我知道不推荐),我仍然不能向 API 发送请求,接收以下输出:

I/STATUS: 405
I/MSG: Method Not Allowed

我认为我的allowAllSSL() 函数(HttpsTrustManager 类)会解决问题,因为如果我删除函数调用,我会收到以下错误,这似乎与服务器端的错误匹配:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:239)

现在,您可能认为 GET 请求在 Spring 中没有正确实现,但事实并非如此,因为同样的 GET 请求在 Postman 中也可以正常工作。我相信问题仍然与证书有关,但我无法弄清楚我需要更改什么。这是我的代码:

Spring BOOT 休息控制器

@RestController
@RequestMapping("/post")


public class PostRequest {
    @GetMapping("")
    public String string(@RequestBody ImageRequest newEmployee){
....

ImageRequest 类仅包含三个私有 String 成员。

HttpsTrustManager 类(允许所有 SSL)

package com.example.androidclient;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
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 HttpsTrustManager implements X509TrustManager {
    private static TrustManager[] trustManagers;
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};

    @Override
    public void checkClientTrusted(
            X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {

    }

    @Override
    public void checkServerTrusted(
            X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {

    }

    public boolean isClientTrusted(X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(X509Certificate[] chain) {
        return true;
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return _AcceptedIssuers;
    }

    public static void allowAllSSL() {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }

        });

        SSLContext context = null;
        if (trustManagers == null) {
            trustManagers = new TrustManager[]{new HttpsTrustManager()};
        }

        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }

        HttpsURLConnection.setDefaultSSLSocketFactory(context != null ? context.getSocketFactory() : null);
    }
}

Android 请求

        HttpsTrustManager.allowAllSSL();
        URL url = new URL("https://192.168.1.106:8443/post");
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
        conn.setRequestProperty("Accept", "application/json");
        conn.setDoOutput(true);
        conn.setDoInput(true);

        JSONObject jsonParam = new JSONObject();
        jsonParam.put("location", "Somewhere");
        jsonParam.put("date", "22.05.2020");
        jsonParam.put("imageBytes", strings[0]);


        Log.i("JSON", jsonParam.toString());
        DataOutputStream os = new DataOutputStream(conn.getOutputStream());
        //os.writeBytes(URLEncoder.encode(jsonParam.toString(), "UTF-8"));
        os.writeBytes(jsonParam.toString());

        os.flush();
        os.close();

        Log.i("STATUS", String.valueOf(conn.getResponseCode()));
        Log.i("MSG", conn.getResponseMessage());

        conn.disconnect();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "ok";
}

【问题讨论】:

    标签: java android spring spring-boot ssl


    【解决方案1】:

    在您的 android 应用程序中使用此功能。

    请注意,这将允许所有 ssl 证书无需验证。我鼓励您在处理此处概述的自签名证书时遵循推荐的方法:https://developer.android.com/training/articles/security-ssl#java

    // Create a trust manager that does not validate certificate chains
    final TrustManager[] trustAllCerts = new TrustManager[] {
    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 new X509Certificate[0];
    }
    }
    };
    
    // Install the all-trusting trust manager
    final SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
    // Create an ssl socket factory with our all-trusting manager
    final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    

    【讨论】:

    • 抱歉,您的方法会导致以下异常:javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found。我认为我用来绕过 SSL 验证的方法更好。此外,this 也在工作。
    【解决方案2】:

    我自己找到了解决方案。 显然,Connection.setDoOutput(true) 方法仅适用于 POSTPUT 请求,但不适用于 GET

    因此,我将RequestMapping 更改为POST,例如:

    @RequestMapping(
        value = "/post",
        produces = "application/json",
        method = RequestMethod.POST)
    

    现在我收到200 OK

    【讨论】:

      猜你喜欢
      • 2021-03-26
      • 1970-01-01
      • 2020-10-15
      • 2021-03-27
      • 2018-09-07
      • 2014-11-25
      • 1970-01-01
      • 2014-10-11
      • 2018-08-18
      相关资源
      最近更新 更多