Android Advanced (III) android httpClient サポート HTTPSアクセスメソッド
プロジェクト内のAndroid httpsリクエストアドレスでこの例外が発生しました(端末認証がない)。
javax.net.ssl.SSLPeerUnverifiedException: ピア証明書がない
は、SSLプロトコルのエンドポイント認証がありません。
問題に遭遇していないので、どうしようもないのですが、いろいろな問題、いろいろなことが絡み合っています。
偉人のブログをいくつも読んで得た解答は以下の通りです。
<span style="font-family:Times New Roman;font-size:14px;">/**
* Post request to connect to Https service
* @param serverURL request address
* @param jsonStr request message
* @return
* @throws Exception
*/
public static synchronized String doHttpsPost(String serverURL, String jsonStr)throws Exception {
<span style="color:#009900;">// Parameters </span>
HttpParams httpParameters = new BasicHttpParams();
<span style="color:#33cc00;"> </span><span style="color:#009900;">// Set connection timeout </span>
HttpConnectionParams.setConnectionTimeout(httpParameters, 3000);
<span style="color:#009900;">// set socket timeout </span>
HttpConnectionParams.setSoTimeout(httpParameters, 3000);
<span style="color:#009900;">// Get HttpClient object (authentication) </span>
HttpClient hc = initHttpClient(httpParameters);
HttpPost post = new HttpPost(serverURL);
<span style="color:#006600;"> </span><span style="color:#009900;">// Send data type </span>
post.addHeader("Content-Type", "application/json;charset=utf-8");
<span style="color:#009900;"> // Accept data types </span>
post.addHeader("Accept", "application/json");
<span style="background-color: rgb(255, 255, 255);"><span style="color:#006600;"> </span><span style="color:#009900;"> // request message </span></span>
StringEntity entity = new StringEntity(jsonStr, "UTF-8");
post.setEntity(entity);
post.setParams(httpParameters);
HttpResponse response = null;
try {
response = hc.execute(post);
} catch (UnknownHostException e) {
throw new Exception("Unable to access " + e.getLocalizedMessage());
} catch (SocketException e) {
e.printStackTrace();
}
int sCode = response.getStatusLine().getStatusCode();
if (sCode == HttpStatus.SC_OK) {
return EntityUtils.toString(response.getEntity());
} else
throw new Exception("StatusCode is " + sCode);
}
private static HttpClient client = null;
/**
* Initialize the HttpClient object
* @param params
* @return
*/
public static synchronized HttpClient initHttpClient(HttpParams params) {
if(client == null){
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryImp(trustStore);
//allow authentication for all hosts
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
// Set http and https support
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
e.printStackTrace();
return new DefaultHttpClient(params);
}
}
return client;
}
public static class SSLSocketFactoryImp extends SSLSocketFactory {
final SSLContext sslContext = SSLContext.getInstance("TLS");
public SSLSocketFactoryImp(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] chain,
String authType)
throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain,
String authType)
throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host,
port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}</span>
ランの下、震える小さな手でテストボタンをクリックし、深呼吸して、えっ?反応なし。SSLPeerUnverifiedExceptionです。ピア証明書がありません。サーバー側のデータは正常に返ってくる。
問題を分析する
HTTPS:Hypertext Secure Transfer Protocol、HTTPと比較して、443番ポートにSSL/TSL認証処理が追加されています。
1. ピアエンドポイントがリクエストを送信し、https サーバはサポートされている暗号化アルゴリズムなどを用いて、証明書(ca の発行者や暗号化された公開鍵などを含む)の形で ID を返します。
2. 証明書取得後、証明書の正当性を確認する。
3. ランダムな鍵を生成し、証明書内の公開鍵で暗号化します。
4. https サーバーにリクエストし、公開鍵で暗号化した鍵を https サーバーに送信します。
5. httpsサーバーが自身の鍵で復号化し、ランダムな値を取得する。
6. その後、双方はこの鍵で暗号化されたデータを送信し、通信を行います。
HTTPSのプロセスが明確になると、問題が明らかになり、証明書を検証する際に、検証することができなくなります。
上記で提供した解決策は、デフォルトのtrust all certificates.を追加することで、次の通信を乗り切ることができます。
しかし、これで問題は解決しました。しかし、まだ信頼できる感じではありません(すべての証明書を信用するのはちょっと危険です)。私はネットでパチパチ検索を続けた。別の解決策が見つかり、以下のような流れになりました。
1. ブラウザはhttpsのアドレスにアクセスし、プロンプトが表示された証明書をローカルに保存し、androidプロジェクトのassetsディレクトリに配置します。
2. 以下のコードで証明書をインポートしてください。
3. 証明書を信頼として追加します。
<span style="font-family:Times New Roman;font-size:14px;">public static String requestHTTPSPage(Context context, String mUrl) {
InputStream ins = null;
String result = "";
try {
ins = context.getAssets().open("my.key"); // The downloaded certificate is placed in the assets directory of the project
CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");
Certificate cer = cerFactory.generateCertificate(ins);
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(null, null);
keyStore.setCertificateEntry("trust", cer);
SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore);
Scheme sch = new Scheme("https", socketFactory, 443);
HttpClient mHttpClient = new DefaultHttpClient();
mHttpClient.getConnectionManager().getSchemeRegistry().register(sch);
BufferedReader reader = null;
try {
HttpGet request = new HttpGet();
request.setURI(new URI(mUrl));
HttpResponse response = mHttpClient.execute(request);
if (response.getStatusLine().getStatusCode() ! = 200) {
request.abort();
return result;
}
reader = new BufferedReader(new InputStreamReader(response
.getEntity().getContent()));
StringBuffer buffer = new StringBuffer();
String line = null;
while ((line = reader.readLine()) ! = null) {
buffer.append(line);
}
result = buffer.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader ! = null) {
reader.close();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ins ! = null)
ins.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result; </span>
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ハートビート・エフェクトのためのHTML+CSS
-
HTML ホテル フォームによるフィルタリング
-
HTML+cssのボックスモデル例(円、半円など)「border-radius」使いやすい
-
HTMLテーブルのテーブル分割とマージ(colspan, rowspan)
-
ランダム・ネームドロッパーを実装するためのhtmlサンプルコード
-
Html階層型ボックスシャドウ効果サンプルコード
-
QQの一時的なダイアログボックスをポップアップし、友人を追加せずにオンラインで話す効果を達成する方法
-
sublime / vscodeショートカットHTMLコード生成の実装
-
HTMLページを縮小した後にスクロールバーを表示するサンプルコード
-
html のリストボックス、テキストフィールド、ファイルフィールドのコード例