简体   繁体   English

SSLHandshakeException:证书未知(Java Spring 引导和 Android)

[英]SSLHandshakeException: Certificate Unknown (Java Spring Boot & Android)

I have a Spring Boot API that runs locally, with a self-signed certificate, using the HTTPS protocol.我有一个 Spring 启动 API 在本地运行,带有自签名证书,使用 HTTPS 协议。 Obviously, when I send GET Requests from the browser, I receive the io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown error on the server side, which is normal, because the self-signed is not trusted by the browser.显然,当我从浏览器发送GET请求时,我收到io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown错误在服务器端,这是正常的,因为自我-signed 不受浏览器信任。 Postman works just fine for GET and POST . Postman 适用于GETPOST

However, I want to send GET requests from an Android client to the Spring API but, even I've used a function to allow all SSL traffic (yes, I know it's not recommended), I still can't send requests to the API, receiving the following output: However, I want to send GET requests from an Android client to the Spring API but, even I've used a function to allow all SSL traffic (yes, I know it's not recommended), I still can't send requests to the API ,接收如下output:

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

I thought my allowAllSSL() function ( HttpsTrustManager class) would solve the issue, because if I remove the function call, I receive the following error, which seems to match the one on the server side:我认为我的allowAllSSL() function ( HttpsTrustManager类)会解决这个问题,因为如果我删除 function 调用,我会收到以下错误,这似乎与服务器端的错误相匹配:

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)

Now, you may think that the GET request is not implemented correctly in Spring, but it's not true, since the same GET request works just fine from Postman.现在,您可能认为 Spring 中的GET请求没有正确实现,但事实并非如此,因为相同的GET请求在 Postman 中也可以正常工作。 I believe that the problem is still linked to the certificate, but I can't figure out what do I need to change.我相信问题仍然与证书有关,但我无法弄清楚我需要更改什么。 Here is my code:这是我的代码:

Spring BOOT Rest Controller Spring 启动 Rest Controller

@RestController
@RequestMapping("/post")


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

The ImageRequest class contains just three private String members. ImageRequest class 仅包含三个私有String成员。

HttpsTrustManager class (to allow all SSL) HttpsTrustManager class(允许所有 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 Request 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";
}

Use this function in your android application.在您的 android 应用程序中使用此 function。

Please note this will allow all ssl certificates without verification.请注意,这将允许所有 ssl 证书无需验证。 I would encourage you to follow the recommended approach when dealing with self-signed certificates outlined here: https://developer.android.com/training/articles/security-ssl#java我鼓励您在处理此处概述的自签名证书时遵循推荐的方法: 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();

I have found the solution on my own.我自己找到了解决方案。 Apparently, the Connection.setDoOutput(true) method is working just for POST and PUT requests, but not for GET .显然, Connection.setDoOutput(true)方法仅适用于POSTPUT请求,但不适用于GET

Thus, I have changed my RequestMapping to work on POST , like, this:因此,我已将我的RequestMapping更改为在POST上工作,例如:

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

Now I receive 200 OK .现在我收到200 OK

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring 引导捕获 SSLHandshakeException - Spring boot catch SSLHandshakeException 在 Spring 引导中拦截 SSLHandshakeException - Intercept SSLHandshakeException in Spring boot 通过使用自己的密钥库而不是将证书添加到 Java JVM 的默认 cacerts 来解决 SSLHandshakeException certificate_unknown - Resolve SSLHandshakeException certificate_unknown by using own keystore instead of adding certificate to Java JVM's default cacerts Java Spring WS 和 SSLHandshakeException - Java Spring WS and SSLHandshakeException VeriSign签名证书中的Java SSLHandshakeException - Java SSLHandshakeException in VeriSign signed certificate Spring Boot 连接到 AWS RDS MySQL - SSLHandshakeException:收到致命警报:unknown_ca - Spring Boot connection to AWS RDS MySQL - SSLHandshakeException: Received fatal alert: unknown_ca Java Spring Webflux:javax.net.ssl.SSLHandshakeException:空客户端证书链 - Java Spring Webflux: javax.net.ssl.SSLHandshakeException: Empty client certificate chain Java Spring 引导框架上的未知行为 - Unknown behaviour on Java Spring Boot Framework 具有自签名证书的Java SSLHandshakeException - Java SSLHandshakeException with self-signed certificate Docker Java应用程序-SSLHandshakeException /未找到可信证书 - Docker Java application - SSLHandshakeException / No trusted certificate found
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM