httpsポストを実行していますが、ssl例外の例外が発生します。信頼されていないサーバー証明書です。通常のhttpを実行すると、完全に正常に動作します。どういうわけかサーバー証明書を受け入れる必要がありますか?
httpsポストを実行していますが、ssl例外の例外が発生します。信頼されていないサーバー証明書です。通常のhttpを実行すると、完全に正常に動作します。どういうわけかサーバー証明書を受け入れる必要がありますか?
回答:
私は推測していますが、実際のハンドシェイクを発生させたい場合は、androidに証明書を通知する必要があります。どうしても受け入れたい場合は、この疑似コードを使用して、Apache HTTPクライアントで必要なものを取得します。
SchemeRegistry schemeRegistry = new SchemeRegistry ();
schemeRegistry.register (new Scheme ("http",
PlainSocketFactory.getSocketFactory (), 80));
schemeRegistry.register (new Scheme ("https",
new CustomSSLSocketFactory (), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager (
params, schemeRegistry);
return new DefaultHttpClient (cm, params);
CustomSSLSocketFactory:
public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory
{
private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory ();
public CustomSSLSocketFactory ()
{
super(null);
try
{
SSLContext context = SSLContext.getInstance ("TLS");
TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () };
context.init (null, tm, new SecureRandom ());
FACTORY = context.getSocketFactory ();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public Socket createSocket() throws IOException
{
return FACTORY.createSocket();
}
// TODO: add other methods like createSocket() and getDefaultCipherSuites().
// Hint: they all just make a call to member FACTORY
}
FullX509TrustManagerはjavax.net.ssl.X509TrustManagerを実装するクラスですが、どのメソッドも実際には何も実行しません。ここでサンプルを取得してください。
幸運を!
FullX509TrustManager
これは私がやっていることです。それは単に証明書をもうチェックしません。
// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
/**
* Trust every server - dont check for any certificate
*/
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
そして
HttpURLConnection http = null;
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
http = https;
} else {
http = (HttpURLConnection) url.openConnection();
}
javax.net.ssl.SSLException: Received fatal alert: bad_record_mac。私も交換TLSしてみましたSSLが、役に立ちませんでした。助けてください、ありがとう
この質問に答えようとしたところ、より良いチュートリアルが見つかりました。これを使用すると、証明書チェックを危険にさらす必要はありません。
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
*私はこれを書きませんでしたが、仕事をしてくれたボブ・リーに感謝します
crazybobsによく似た私のブログ記事もご覧ください。
このソリューションは、証明書チェックを危険にさらすこともなく、信頼できる証明書を独自のキーストアに追加する方法を説明します。
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
礼儀マドゥランガ
httpsを使用するアプリケーションを開発する場合、テストサーバーに有効なSSL証明書がありません。または、Webサイトが自己署名証明書を使用している場合や、Webサイトが無料のSSL証明書を使用している場合があります。したがって、Apacheを使用してサーバーに接続しようとするHttpClientと、「ピアが認証されていない」という例外が発生します。運用ソフトウェアのすべての証明書を信頼することはお勧めできませんが、状況によってはそうする必要がある場合があります。このソリューションは、「ピアが認証されていない」ことによって引き起こされる例外を解決します。
しかし、解決策に進む前に、これは運用アプリケーションにとっては良い考えではないことを警告しなければなりません。これは、セキュリティ証明書を使用する目的に違反します。したがって、正当な理由がない限り、またはこれが問題を引き起こさないことが確実である場合を除いて、このソリューションは使用しないでください。
通常、あなたはHttpClientこのようなものを作成します。
HttpClient httpclient = new DefaultHttpClient();
ただし、HttpClientの作成方法を変更する必要があります。
まず、拡張するクラスを作成する必要がありますorg.apache.http.conn.ssl.SSLSocketFactory。
import org.apache.http.conn.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
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();
}
}
次に、このようなメソッドを作成します。
public HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
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) {
return new DefaultHttpClient();
}
}
次に、を作成できますHttpClient。
HttpClient httpclient = getNewHttpClient();
ログインページに投稿リクエストを送信する場合、残りのコードは次のようになります。
private URI url = new URI("url of the action of the form");
HttpPost httppost = new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", "user"));
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HTMLページをInputStreamに取得します。次に、返されたhtmlページで何でも好きなことができます。
しかし、ここで問題に直面します。Cookieを使用してセッションを管理する場合は、この方法では管理できません。クッキーを取得したい場合は、ブラウザで取得する必要があります。その後、あなただけがクッキーを受け取ります。
StartSSLまたはThawte証明書を使用している場合、Froyo以前のバージョンでは失敗します。すべての証明書を信頼する代わりに、新しいバージョンのCAcertリポジトリを使用できます。
これらはどれもうまくいきませんでした(Thawteバグによっても悪化しました)。最終的に私はそれをAndroidでの自己署名SSL受け入れで修正し、カスタムSSL処理はAndroid 2.2 FroYoで動作しなくなりました
この答えはどれもうまくいきませんでしたので、証明書を信頼するコードを次に示します。
import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class HttpsClientBuilder {
public static DefaultHttpClient getBelieverHttpsClient() {
DefaultHttpClient client = null;
SchemeRegistry Current_Scheme = new SchemeRegistry();
Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
try {
Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443));
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HttpParams Current_Params = new BasicHttpParams();
int timeoutConnection = 8000;
HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection);
int timeoutSocket = 10000;
HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket);
ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme);
client = new DefaultHttpClient(Current_Manager, Current_Params);
//HttpPost httpPost = new HttpPost(url);
//client.execute(httpPost);
return client;
}
public static class Naive_SSLSocketFactory extends SSLSocketFactory
{
protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS");
public Naive_SSLSocketFactory ()
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException
{
super(null, null, null, null, null, (X509HostnameVerifier)null);
Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException
{
return Cur_SSL_Context.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException
{
return Cur_SSL_Context.getSocketFactory().createSocket();
}
}
private static class X509_Trust_Manager implements X509TrustManager
{
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
};
}
Androidのssl証明書の詳細については知りませんが、Androidがすぐに自己署名されたssl証明書を受け入れないのは理にかなっています。私は同じ問題に対処しているように見えるアンドロイドフォーラムからこの投稿を見つけました:http : //androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html
これはAndroid 2.xの既知の問題です。次の質問に出会うまで、私はこの問題に1週間も取り組んでいました。これは、問題の良い背景を提供するだけでなく、セキュリティホールのない実用的で効果的なソリューションを提供します。
何らかの理由で、上記のhttpClientについて述べた解決策がうまくいきませんでした。最後に、カスタムSSLSocketFactoryクラスを実装するときにメソッドを正しくオーバーライドすることで、このメソッドを機能させることができました。
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
throws IOException, UnknownHostException
{
return sslFactory.createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslFactory.createSocket();
}
これは私にとって完璧に機能した方法です。次のスレッドで完全なカスタムクラスと実装を確認できます。http: //blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
このクラスを作って見つけた
package com.example.fakessl;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import android.util.Log;
public class CertificadoAceptar {
private static TrustManager[] trustManagers;
public static class _FakeX509TrustManager implements
javax.net.ssl.X509TrustManager {
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return (true);
}
public boolean isServerTrusted(X509Certificate[] chain) {
return (true);
}
public X509Certificate[] getAcceptedIssuers() {
return (_AcceptedIssuers);
}
}
public static void allowAllSSL() {
javax.net.ssl.HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
javax.net.ssl.SSLContext context = null;
if (trustManagers == null) {
trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
}
try {
context = javax.net.ssl.SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
Log.e("allowAllSSL", e.toString());
} catch (KeyManagementException e) {
Log.e("allowAllSSL", e.toString());
}
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
}
}
あなたはこれをコード化します
CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
AWS Apacheサーバーで自己署名証明書を操作し、AndroidデバイスからHttpsURLConnectionに接続するのに役立つソース:AWS
インスタンス
でのSSL - HTTPSおよびSSLを使用したssl Android Securityの Amazonチュートリアル-受け入れるためのクライアントでの独自の信頼マネージャーの作成証明書
自己署名証明書の作成 - 証明書を作成するための簡単なスクリプト
それから私は次のことをしました:
create_my_certs.sh。#!/bin/bash FQDN=$1 # make directories to work from mkdir -p server/ client/ all/ # Create your very own Root Certificate Authority openssl genrsa \ -out all/my-private-root-ca.privkey.pem \ 2048 # Self-sign your Root Certificate Authority # Since this is private, the details can be as bogus as you like openssl req \ -x509 \ -new \ -nodes \ -key all/my-private-root-ca.privkey.pem \ -days 1024 \ -out all/my-private-root-ca.cert.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com" # Create a Device Certificate for each domain, # such as example.com, *.example.com, awesome.example.com # NOTE: You MUST match CN to the domain name or ip address you want to use openssl genrsa \ -out all/privkey.pem \ 2048 # Create a request from your Device, which your Root CA will sign openssl req -new \ -key all/privkey.pem \ -out all/csr.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}" # Sign the request from Device with your Root CA openssl x509 \ -req -in all/csr.pem \ -CA all/my-private-root-ca.cert.pem \ -CAkey all/my-private-root-ca.privkey.pem \ -CAcreateserial \ -out all/cert.pem \ -days 500 # Put things in their proper place rsync -a all/{privkey,cert}.pem server/ cat all/cert.pem > server/fullchain.pem # we have no intermediates in this case rsync -a all/my-private-root-ca.cert.pem server/ rsync -a all/my-private-root-ca.cert.pem client/
bash create_my_certs.sh yourdomain.com証明書をサーバーの適切な場所に配置します(構成は/etc/httpd/conf.d/ssl.confにあります)。これらはすべて設定する必要があります:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
を使用sudo service httpd restartしてhttpdを再起動し、httpdが開始されていることを確認します
。httpdの停止:[OK]
httpdの開始:[OK]
my-private-root-ca.certAndroidプロジェクトアセットフォルダーにコピーする
信頼マネージャーを作成します。
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance( "X.509"); InputStream caInput = context.getAssets()。open( "my-private-root-ca.cert.pem"); 証明書ca; {ca = cf.generateCertificate(caInput);を試してください。}最後に{caInput.close(); }
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext = SSLContext.getInstance("TLS");
SSSLContext.init(null, tmf.getTrustManagers(), null);そして、HttpsURLConnectionを使用して接続を作成します。
HttpsURLConnection接続=(HttpsURLConnection)url.openConnection(); connection.setSSLSocketFactory(SSLContext.getSocketFactory());
それで、https接続を試してください。
このメソッドをHTTPClientとして使用するだけです。
public static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
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) {
return new DefaultHttpClient();
}
}