10

REST API を呼び出そうとしていますが、次の例外が発生します (最後に StackTrace が完了します)。

"javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"

この問題について API プロバイダーに問い合わせたところ、使用している SSL ライブラリに問題があるとのことでした。

この問題をどのように解決しますか?この同じコード (以下) を使用して、問題なく NIMBLE API REST を呼び出しましたが、この場合は機能しません。次に、ファイル証明書 (.cer) がありません。

セキュリティ メソッドは既に持っている API KEY であるため、SSL 検証を無効にする必要があります。

助言がありますか?

どうもありがとうございました!

==== コンソール: ====

POST https://api.nexalogy.com/project/create?api_key=XXXXXXXXXXXXXXXXXXXX
HTTP Header:"Content-Type" "application/json"
HTTP Body:[{"name":"project1","lang":"en","type":"twitter"}]
api_key:XXXXXXXXXXXXXXXXXXXX
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

次のフォームも試しましたが、例外は同じです。

POST https://api.nexalogy.com/project/create
HTTP Header:"Content-Type" "application/json"
HTTP Header:"api_key" "XXXXXXXXXXXXXXXXXXXX"
HTTP Body:[{"name":"project1","lang":"en","type":"twitter"}]
api_key:XXXXXXXXXXXXXXXXXXXX
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

==== コード: ====

package servlet;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/AddProject")
public class AddProject extends HttpServlet {
    private static final long serialVersionUID = 1L;
    public AddProject() {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String body="[{\"name\":\"project1\",\"lang\":\"en\",\"type\":\"twitter\"}]";
        String api_key="XXXXXXXXXXXXXXXXXXXX";
        String str_response="";
        String line="";
        URL url = new URL("https://api.nexalogy.com/project/create?api_key="+api_key);
        try{
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type","application/json");
            System.out.println("POST https://api.nexalogy.com/project/create?api_key="+api_key);
            System.out.println("HTTP Header:"+"\"Content-Type\" \"application/json\"");
            System.out.println("HTTP Body:"+body);
            System.out.println("api_key:"+api_key);
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.writeBytes(body);
            wr.flush();
            wr.close();
            InputStream is = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader rd = new BufferedReader(isr);
            while ((line = rd.readLine()) != null) str_response+= line + '\r';
            rd.close();
            System.out.println("str_response:"+str_response);
        }catch(Exception e){
            e.printStackTrace(System.out);
            //throw new RuntimeException(e);
        }
    }
}

==== 完全な StackTrace: ====

com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:131)
    at com.sun.jersey.api.client.Client.handle(Client.java:616)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:559)
    at com.sun.jersey.api.client.WebResource.post(WebResource.java:230)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.tREST_2Process(Twitter_api_create_project.java:955)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.tJava_1Process(Twitter_api_create_project.java:635)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.runJobInTOS(Twitter_api_create_project.java:1641)
    at engine_brandchats.twitter_api_create_project_0_1.Twitter_api_create_project.main(Twitter_api_create_project.java:1494)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler$1$1.getOutputStream(URLConnectionClientHandler.java:203)
    at com.sun.jersey.api.client.CommittingOutputStream.commitWrite(CommittingOutputStream.java:117)
    at com.sun.jersey.api.client.CommittingOutputStream.write(CommittingOutputStream.java:89)
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlush(Unknown Source)
    at sun.nio.cs.StreamEncoder.flush(Unknown Source)
    at java.io.OutputStreamWriter.flush(Unknown Source)
    at java.io.BufferedWriter.flush(Unknown Source)
    at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191)
    at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128)
    at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88)
    at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58)
    at com.sun.jersey.api.client.TerminatingClientHandler.writeRequestEntity(TerminatingClientHandler.java:305)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:182)
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:129)
    ... 7 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    ... 35 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 41 more

EDITED 2013-06-13 解決策: X509TrustManager を実装する

次のコードを追加します...

HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
if (connection instanceof HttpsURLConnection) {
    try {
        KeyManager[] km = null;
        TrustManager[] tm = {new RelaxedX509TrustManager()};
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, tm, new java.security.SecureRandom());
        SSLSocketFactory sf = sslContext.getSocketFactory();
        ((HttpsURLConnection)connection).setSSLSocketFactory(sf);
        System.out.println("setSSLSocketFactory OK!");
    }catch (java.security.GeneralSecurityException e) {
        System.out.println("GeneralSecurityException: "+e.getMessage());
    }
}

...そして次のクラスを追加します(X509TrustManagerを実装します)

class RelaxedX509TrustManager implements X509TrustManager {
    public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){ return true; }
    public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){ return true; }
    public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String input) {}
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String input) {}
}
4

3 に答える 3

3

セキュリティ メソッドは既に持っている API KEY であるため、SSL 検証を無効にする必要があります。

API キー (およびそれが提供するセキュリティの側面) が SSL/TLS によって提供されるセキュリティとどのように関係していると思うかは明確ではありません: それらは確かに同じセキュリティの側面に対処していません. SSL/TLS は、データ転送を盗聴や改ざんから保護するためのものです。

この SSL テスト サービスに対して接続しようとしているサーバーを確認すると、そのサーバーには Server Name Indication (SNI) をサポートするクライアントが必要であることがわかります。これにより、サーバーは異なる証明書を持つ複数のホストをホストできます。

クライアントが SNI をサポートしていない場合 (Java はバージョン 7 以降のクライアント側でのみサポートしています)、要求はインデントされたものとは異なる証明書で提示されます: 証明書の検証またはホスト名の検証手順のいずれかに失敗する可能性があります。いずれかのチェックを無効にすると、接続が中間者攻撃に対して脆弱になります。

  • あなたが抱えている問題の最も可能性の高い原因は、SNI をサポートしていないバージョンの Java (Java 6 など) を使用していることだと思います。

  • また、使用している JRE のデフォルトのトラスト ストアにこの特定の CA がない可能性もあります。別のソース (cURL でよく推奨される Mozilla バンドルなど) から、信頼できる CA 証明書のリストを変換して取得することもできます。最初に CA 証明書とは何かを理解する必要がある場合があります。

    JSSEリファレンスガイドが言うように:

    重要な注意: JDK は、/lib/security/cacerts ファイル内に限られた数の信頼できるルート証明書と共に出荷されます。keytool に記載されているように、このファイルをトラストストアとして使用する場合、このファイルに含まれる証明書を維持 (つまり、追加/削除) するのはユーザーの責任です。

    接続するサーバーの証明書構成によっては、追加のルート証明書を追加する必要がある場合があります。適切なベンダーから必要な特定のルート証明書を取得します。

いずれにせよ、SSL 検証を無効にしても問題の解決にはなりません。

編集:

使用しようとしているサービスには、明らかに Oracle JRE にデフォルトでバンドルされている CA の 1 つではない StartSSL によって発行された証明書があるようです。

StartSSLからダウンロードする必要があります(または、既に持っている信頼できるバンドルからエクスポートします。「StartCom ...」と呼ばれます) cacerts。 1):

keytool -import -keystore /path/to/jre/lib/security/cacerts -alias startssl -file startssl.crt

(もちろん、必要に応じて、startssl 証明書ファイルのパスと名前を変更します。)

于 2013-06-12T14:10:31.187 に答える