当使用SSL连接到HAProxy服务器时,我会出现随机出现的连接失败.我已经确认这些故障发生在JDK版本1.7.0_21和1.7.0_25上,但不是1.7.0_04或1.6.0_38.
例外是
Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)
at SSLTest2.main(SSLTest2.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Run Code Online (Sandbox Code Playgroud)
这些故障仅在使用TLS SSL上下文而非默认上下文时发生.以下代码在循环中运行了一千次,并且在循环完成之前发生了故障(大约2%的连接失败):
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, null, null);
SSLSocketFactory factory = sslcontext.getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket("myserver", 443);
//socket.startHandshake();
SSLSession session = socket.getSession();
session.getPeerCertificates();
socket.close();
Run Code Online (Sandbox Code Playgroud)
但是,如果我以这种方式创建SSL上下文,我在上面提到的任何Java版本上都没有连接失败:
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
Run Code Online (Sandbox Code Playgroud)
第一种方式使用SSLContextImpl$TLS10Context
和后来使用SSLContextImpl$DefaultSSLContext
.查看代码,我没有看到任何会导致异常发生的差异.
为什么我会得到失败以及使用getDefault()
呼叫的优点/缺点是什么?
注意:首先使用Apache HttpClient(版本4)看到了异常.此代码是再现HttpClient所遇问题的最小子集.
这是我在添加时看到的错误-Djavax.net.debug=ssl
:
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, …
Run Code Online (Sandbox Code Playgroud) 我正在尝试在Android应用中创建SSLSocket
另一个SSLSocket
.较低的连接是与安全Web代理(基于SSL的HTTP代理)的SSL安全连接,上层连接用于HTTP over SSL(HTTPS).
为此,我正在使用SSLSocketFactory的createSocket()
函数,它允许传递一个现有的Socket来运行SSL连接,如下所示:
private Socket doSSLHandshake(Socket socket, String host, int port) throws IOException {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){ return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, true);
sslSocket.setEnabledProtocols(sslSocket.getSupportedProtocols());
sslSocket.setEnableSessionCreation(true);
sslSocket.startHandshake();
return sslSocket;
} catch (KeyManagementException | NoSuchAlgorithmException …
Run Code Online (Sandbox Code Playgroud) 我正在开发一款需要客户端证书身份验证(包含PKCS 12文件)的Android应用.随着所有这些的弃用apache.http.*
,我们已经开始在我们的网络层上进行重构,我们决定使用OkHttp作为替代品,到目前为止我非常喜欢它.
但是,我没有找到任何其他方法来处理客户端证书auth而不使用SSLSocketFactory
OkHttp或其他任何事情.那么在这种特殊情况下,最好的做法是什么?OkHttp有另一种方法来处理这种身份验证吗?
由于POODLE漏洞,我在Amazon AWS中托管的服务器不再支持SSLv3.
因此,我的Android应用程序对服务器执行的第一个HTTPS连接会在建立连接时导致错误.
Error reading server response: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x77d8ab68: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x7339ad74:0x00000000)
[....]
Caused by: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x77d8ab68: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x7339ad74:0x00000000)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
at com.android.okhttp.Connection.connect(Connection.java:107)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
Run Code Online (Sandbox Code Playgroud)
该错误仅在第一个请求中发生.后续请求工作了一段时间.
为了解决这个问题,我试图从Android客户端接受的协议列表中删除SSL,并确保我只使用TLS.为此,我设置了一个自定义SSLSocketFactory,它从启用的协议和支持的密码套件列表中删除SSL.
/**
* SSLSocketFactory that wraps one existing SSLSocketFactory and delegetes into it …
Run Code Online (Sandbox Code Playgroud) ssl android amazon-web-services sslsocketfactory poodle-attack
我编写了一个基于Java SSLServerSocket的服务器,它接受连接并通过自定义二进制协议与Android应用程序通信:
ServerSocket serverSocket = SSLServerSocketFactory.getDefault().createServerSocket(1234);
while (true) {
Socket socket = serverSocket.accept();
...
}
Run Code Online (Sandbox Code Playgroud)
我使用以下参数运行服务器:
-Djavax.net.ssl.keyStore=keystore.jks
-Djavax.net.ssl.keyStorePassword=<PASSWORD>
Run Code Online (Sandbox Code Playgroud)
并使用以下教程生成证书,该教程构建公钥和私钥集:http://judebert.com/progress/archives/425-Using-SSL-in-Java,-Part-2.html:
keytool -genkeypair -keystore keystore.jks -alias keyname
keytool -export -alias keyname -file keyname.crt -keystore keystore.jks
keytool -importcert -file keyname.crt -keystore truststore.jks
Run Code Online (Sandbox Code Playgroud)
另外,我通过使用bouncycastle构建一个信任库来使它与android兼容:
keytool -importkeystore -srckeystore truststore.jks -srcstoretype JKS -srcstorepass <PASSWORD> -destkeystore truststore.bks -deststoretype BKS -deststorepass <PASSWORD> -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-1.58.jar
Run Code Online (Sandbox Code Playgroud)
在此下载bouncycastle提供商:https://www.bouncycastle.org/latest_releases.html
并将生成的truststore.bks移动到原始资源文件夹中.
在Android上我使用以下代码构建一个SSLSocketFactory
允许我导入生成的bouncycastle证书,该证书对我的服务器进行身份验证:
KeyStore trustStore = KeyStore.getInstance("BKS");
InputStream trustStoreStream = context.getResources().openRawResource(R.raw.truststore);
trustStore.load(trustStoreStream, "<PASSWORD>".toCharArray()); …
Run Code Online (Sandbox Code Playgroud) 我正在加密服务器和客户端之间的TCP连接.在研究和测试过程中,我倾向于使用密钥加密.我的问题是我找不到任何有关如何实现此功能的教程.我发现的教程围绕一次性https请求,我只需要一个SSL Socket.
我到目前为止编写的代码如下.我几乎可以肯定它需要扩展,我只是不知道如何.任何帮助表示赞赏.
private ServerSocketFactory factory;
private SSLServerSocket serverSocket;
factory = SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket) factory.createServerSocket( <portNum> );
Run Code Online (Sandbox Code Playgroud)
用于接受客户端连接的服务器代码
SSLSocket socket = (SSLSocket) serverSocket.accept();
socket.startHandshake();
Run Code Online (Sandbox Code Playgroud)
我只是不知道如何实际握手.
参考:http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html
我的项目已经使用Android Volley网络框架很长一段时间了,但最近我发现了Internet上发布的SSL 3.0协议错误.
我想知道如何找出我的项目使用的TLS版本,以及如何确认库是否更新.
这是我的源代码片段:
HttpStack stack = new HurlStack();
Network network = new BasicNetwork(stack);
mHttpRequestQueue = new RequestQueue(new NoCache(), network);
mHttpRequestQueue.start();
Run Code Online (Sandbox Code Playgroud)
我认为重点在于HurlStack类,它取决于org.apache.http
包,但我无法弄清楚TLS/SSL配置的位置.
SSLSocketFactory
提供getDefaultCipherSuites
(在套接字上默认启用的getSupportedCipherSuites
密码)和(如果需要,可以启用的密码).
但是,SSLSocketFactory
不提供setEnabledCipherSuites
配置密码列表一次以在后续套接字上提供首选项.
事实上,我认为制造setEnabledCipherSuites
一部分SSLSocket
非常复杂.例如,HttpsURLConnection
没有提供getSocket
,它确实打破了这个流程:
...
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManager.getTrustManagers(), null);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(context.getSocketFactory());
Run Code Online (Sandbox Code Playgroud)
我认为同样可以说,SSLContext
因为它有像getDefaultSSLParameters
和的方法getSupportedSSLParameters
.
我正试图为(in)能力提出一个合理的安全工程理由,但我不能.也许是决定软件工程的原因.(我怀疑这是一个很好的理由,而且我目前缺乏洞察力).
为什么Java缺乏配置的能力SSLSocketFactory
?它显然是一个设计决策,我试图理解为什么它是以牺牲图书馆相关部分的安全性为代价的.
我得到了一个自签名的客户端证书工具包,该工具包将用于通过HTTPS访问服务器。该套件包含以下PEM文件:
解决任务的一种方法是生成Java密钥库:
...然后使用类似以下的代码来构建SSLSocketFactory实例:
InputStream stream = new ByteArrayInputStream(pksData);
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(stream, password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(keyStore);
TrustManager[] trustManagers = tmfactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
sslSocketFactory = sslContext.getSocketFactory();
Run Code Online (Sandbox Code Playgroud)
...以后用于初始化http库。
因此,我们获得了一个KeyStore,然后在其帮助下初始化KeyManagers和TrustManagers,最后我们用它们构建SSLSocketFactory实例。
问题是:是否有一种方法可以避免创建密钥库文件,并以某种方式从PublicKey和Certificate实例开始构建SSLSocketFactory(例如,可以使用bouncycastle的PemReader从PEM文件中获取)?
在 OkHttp3 中,不推荐使用以下内容[A]:
sslSocketFactory(SSLSocketFactory sslSocketFactory)
Run Code Online (Sandbox Code Playgroud)
它被替换为[B]:
sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager).
Run Code Online (Sandbox Code Playgroud)
以下是我的问题:
有什么用的X509TrustManager在[B] ?
在创建SSLSocketFactory对象时已经可以指定 TrustManager 时,使用[B]而不是[A]的优点是什么?
在https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.Builder.html#sslSocketFactory-javax.net.ssl.SSLSocketFactory- 他们谈到在使用[B]时避免反射,有人可以解释?
更多信息:
创建SSLSocketFactory对象时,已经可以在
sslContext.init(KeyManager[] arg0, TrustManager[] arg1, SecureRandom arg2).
Run Code Online (Sandbox Code Playgroud)
例如,我通过执行以下操作获得SSLSocketFactory对象:
public SSLSocketFactory getSSLSocketFactory() {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(getKeyManager(), getTrustManager(), new SecureRandom());
return sslContext.getSocketFactory();
}
Run Code Online (Sandbox Code Playgroud)
使用getTrustManager ()返回一个TrustManager[] 的方法,其中包含客户端应该信任的服务器证书。
现在,既然
sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
Run Code Online (Sandbox Code Playgroud)
希望我提供一个X509TrustManager对象,我通过以下方式处理:
OkHttpClient okClient = …
Run Code Online (Sandbox Code Playgroud) sslsocketfactory ×10
ssl ×8
java ×7
android ×5
cryptography ×1
encryption ×1
haproxy ×1
https ×1
keystore ×1
okhttp ×1
okhttp3 ×1
pem ×1
pkcs#12 ×1
sockets ×1