Accept server's self-signed ssl certificate in Java client

后端 未结 12 1484
日久生厌
日久生厌 2020-11-22 00:04

It looks like a standard question, but I couldn\'t find clear directions anywhere.

I have java code trying to connect to a server with probably self-signed (or expir

12条回答
  •  清酒与你
    2020-11-22 00:32

    The accepted answer needs an Option 3

    ALSO Option 2 is TERRIBLE. It should NEVER be used (esp. in production) since it provides a FALSE sense of security. Just use HTTP instead of Option 2.

    OPTION 3

    Use the self-signed certificate to make the Https connection.

    Here is an example:

    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.URL;
    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateException;
    import java.security.cert.CertificateFactory;
    import java.security.KeyStore;
    
    /*
     * Use a SSLSocket to send a HTTP GET request and read the response from an HTTPS server.
     * It assumes that the client is not behind a proxy/firewall
     */
    
    public class SSLSocketClientCert
    {
        private static final String[] useProtocols = new String[] {"TLSv1.2"};
        public static void main(String[] args) throws Exception
        {
            URL inputUrl = null;
            String certFile = null;
            if(args.length < 1)
            {
                System.out.println("Usage: " + SSLSocketClient.class.getName() + " ");
                System.exit(1);
            }
            if(args.length == 1)
            {
                inputUrl = new URL(args[0]);
            }
            else
            {
                inputUrl = new URL(args[0]);
                certFile = args[1];
            }
            SSLSocket sslSocket = null;
            PrintWriter outWriter = null;
            BufferedReader inReader = null;
            try
            {
                SSLSocketFactory sslSocketFactory = getSSLSocketFactory(certFile);
    
                sslSocket = (SSLSocket) sslSocketFactory.createSocket(inputUrl.getHost(), inputUrl.getPort() == -1 ? inputUrl.getDefaultPort() : inputUrl.getPort());
                String[] enabledProtocols = sslSocket.getEnabledProtocols();
                System.out.println("Enabled Protocols: ");
                for(String enabledProtocol : enabledProtocols) System.out.println("\t" + enabledProtocol);
    
                String[] supportedProtocols = sslSocket.getSupportedProtocols();
                System.out.println("Supported Protocols: ");
                for(String supportedProtocol : supportedProtocols) System.out.println("\t" + supportedProtocol + ", ");
    
                sslSocket.setEnabledProtocols(useProtocols);
    
                /*
                 * Before any data transmission, the SSL socket needs to do an SSL handshake.
                 * We manually initiate the handshake so that we can see/catch any SSLExceptions.
                 * The handshake would automatically  be initiated by writing & flushing data but
                 * then the PrintWriter would catch all IOExceptions (including SSLExceptions),
                 * set an internal error flag, and then return without rethrowing the exception.
                 *
                 * This means any error messages are lost, which causes problems here because
                 * the only way to tell there was an error is to call PrintWriter.checkError().
                 */
                sslSocket.startHandshake();
                outWriter = sendRequest(sslSocket, inputUrl);
                readResponse(sslSocket);
                closeAll(sslSocket, outWriter, inReader);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                closeAll(sslSocket, outWriter, inReader);
            }
        }
    
        private static PrintWriter sendRequest(SSLSocket sslSocket, URL inputUrl) throws IOException
        {
            PrintWriter outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sslSocket.getOutputStream())));
            outWriter.println("GET " + inputUrl.getPath() + " HTTP/1.1");
            outWriter.println("Host: " + inputUrl.getHost());
            outWriter.println("Connection: Close");
            outWriter.println();
            outWriter.flush();
            if(outWriter.checkError())        // Check for any PrintWriter errors
                System.out.println("SSLSocketClient: PrintWriter error");
            return outWriter;
        }
    
        private static void readResponse(SSLSocket sslSocket) throws IOException
        {
            BufferedReader inReader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
            String inputLine;
            while((inputLine = inReader.readLine()) != null)
                System.out.println(inputLine);
        }
    
        // Terminate all streams
        private static void closeAll(SSLSocket sslSocket, PrintWriter outWriter, BufferedReader inReader) throws IOException
        {
            if(sslSocket != null) sslSocket.close();
            if(outWriter != null) outWriter.close();
            if(inReader != null) inReader.close();
        }
    
        // Create an SSLSocketFactory based on the certificate if it is available, otherwise use the JVM default certs
        public static SSLSocketFactory getSSLSocketFactory(String certFile)
            throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException
        {
            if (certFile == null) return (SSLSocketFactory) SSLSocketFactory.getDefault();
            Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(new File(certFile)));
    
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("server", certificate);
    
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
    
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
    
            return sslContext.getSocketFactory();
        }
    }
    
    

提交回复
热议问题