
通过使用wireshark分析数据包,我找到了解决方案。我发现,在建立安全连接的同时,android从TLSv1退回到SSLv3。这是Android版本<4.4中的错误,可以通过从“启用的协议”列表中删除SSLv3协议来解决。我制作了一个名为NoSSLv3SocketFactory.java的自定义socketFactory类。使用它来创建一个套接字工厂。
import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.Socket;import java.net.SocketAddress;import java.net.SocketException;import java.nio.channels.SocketChannel;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import javax.net.ssl.HandshakeCompletedListener;import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLSession;import javax.net.ssl.SSLSocket;import javax.net.ssl.SSLSocketFactory;public class NoSSLv3SocketFactory extends SSLSocketFactory{ private final SSLSocketFactory delegate;public NoSSLv3SocketFactory() { this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();}public NoSSLv3SocketFactory(SSLSocketFactory delegate) { this.delegate = delegate;}@Overridepublic String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites();}@Overridepublic String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites();}private Socket makeSocketSafe(Socket socket) { if (socket instanceof SSLSocket) { socket = new NoSSLv3SSLSocket((SSLSocket) socket); } return socket;}@Overridepublic Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));}@Overridepublic Socket createSocket(String host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port));}@Overridepublic Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));}@Overridepublic Socket createSocket(InetAddress host, int port) throws IOException { return makeSocketSafe(delegate.createSocket(host, port));}@Overridepublic Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));}private class NoSSLv3SSLSocket extends DelegateSSLSocket { private NoSSLv3SSLSocket(SSLSocket delegate) { super(delegate); } @Override public void setEnabledProtocols(String[] protocols) { if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) { List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols())); if (enabledProtocols.size() > 1) { enabledProtocols.remove("SSLv3"); System.out.println("Removed SSLv3 from enabled protocols"); } else { System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols)); } protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]); } super.setEnabledProtocols(protocols); }}public class DelegateSSLSocket extends SSLSocket { protected final SSLSocket delegate; DelegateSSLSocket(SSLSocket delegate) { this.delegate = delegate; } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public String[] getEnabledCipherSuites() { return delegate.getEnabledCipherSuites(); } @Override public void setEnabledCipherSuites(String[] suites) { delegate.setEnabledCipherSuites(suites); } @Override public String[] getSupportedProtocols() { return delegate.getSupportedProtocols(); } @Override public String[] getEnabledProtocols() { return delegate.getEnabledProtocols(); } @Override public void setEnabledProtocols(String[] protocols) { delegate.setEnabledProtocols(protocols); } @Override public SSLSession getSession() { return delegate.getSession(); } @Override public void addHandshakeCompletedListener(HandshakeCompletedListener listener) { delegate.addHandshakeCompletedListener(listener); } @Override public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) { delegate.removeHandshakeCompletedListener(listener); } @Override public void startHandshake() throws IOException { delegate.startHandshake(); } @Override public void setUseClientMode(boolean mode) { delegate.setUseClientMode(mode); } @Override public boolean getUseClientMode() { return delegate.getUseClientMode(); } @Override public void setNeedClientAuth(boolean need) { delegate.setNeedClientAuth(need); } @Override public void setWantClientAuth(boolean want) { delegate.setWantClientAuth(want); } @Override public boolean getNeedClientAuth() { return delegate.getNeedClientAuth(); } @Override public boolean getWantClientAuth() { return delegate.getWantClientAuth(); } @Override public void setEnableSessionCreation(boolean flag) { delegate.setEnableSessionCreation(flag); } @Override public boolean getEnableSessionCreation() { return delegate.getEnableSessionCreation(); } @Override public void bind(SocketAddress localAddr) throws IOException { delegate.bind(localAddr); } @Override public synchronized void close() throws IOException { delegate.close(); } @Override public void connect(SocketAddress remoteAddr) throws IOException { delegate.connect(remoteAddr); } @Override public void connect(SocketAddress remoteAddr, int timeout) throws IOException { delegate.connect(remoteAddr, timeout); } @Override public SocketChannel getChannel() { return delegate.getChannel(); } @Override public InetAddress getInetAddress() { return delegate.getInetAddress(); } @Override public InputStream getInputStream() throws IOException { return delegate.getInputStream(); } @Override public boolean getKeepAlive() throws SocketException { return delegate.getKeepAlive(); } @Override public InetAddress getLocalAddress() { return delegate.getLocalAddress(); } @Override public int getLocalPort() { return delegate.getLocalPort(); } @Override public SocketAddress getLocalSocketAddress() { return delegate.getLocalSocketAddress(); } @Override public boolean getOOBInline() throws SocketException { return delegate.getOOBInline(); } @Override public OutputStream getOutputStream() throws IOException { return delegate.getOutputStream(); } @Override public int getPort() { return delegate.getPort(); } @Override public synchronized int getReceiveBufferSize() throws SocketException { return delegate.getReceiveBufferSize(); } @Override public SocketAddress getRemoteSocketAddress() { return delegate.getRemoteSocketAddress(); } @Override public boolean getReuseAddress() throws SocketException { return delegate.getReuseAddress(); } @Override public synchronized int getSendBufferSize() throws SocketException { return delegate.getSendBufferSize(); } @Override public int getSoLinger() throws SocketException { return delegate.getSoLinger(); } @Override public synchronized int getSoTimeout() throws SocketException { return delegate.getSoTimeout(); } @Override public boolean getTcpNoDelay() throws SocketException { return delegate.getTcpNoDelay(); } @Override public int getTrafficClass() throws SocketException { return delegate.getTrafficClass(); } @Override public boolean isBound() { return delegate.isBound(); } @Override public boolean isClosed() { return delegate.isClosed(); } @Override public boolean isConnected() { return delegate.isConnected(); } @Override public boolean isInputShutdown() { return delegate.isInputShutdown(); } @Override public boolean isOutputShutdown() { return delegate.isOutputShutdown(); } @Override public void sendUrgentData(int value) throws IOException { delegate.sendUrgentData(value); } @Override public void setKeepAlive(boolean keepAlive) throws SocketException { delegate.setKeepAlive(keepAlive); } @Override public void setOOBInline(boolean oobinline) throws SocketException { delegate.setOOBInline(oobinline); } @Override public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { delegate.setPerformancePreferences(connectionTime, latency, bandwidth); } @Override public synchronized void setReceiveBufferSize(int size) throws SocketException { delegate.setReceiveBufferSize(size); } @Override public void setReuseAddress(boolean reuse) throws SocketException { delegate.setReuseAddress(reuse); } @Override public synchronized void setSendBufferSize(int size) throws SocketException { delegate.setSendBufferSize(size); } @Override public void setSoLinger(boolean on, int timeout) throws SocketException { delegate.setSoLinger(on, timeout); } @Override public synchronized void setSoTimeout(int timeout) throws SocketException { delegate.setSoTimeout(timeout); } @Override public void setTcpNoDelay(boolean on) throws SocketException { delegate.setTcpNoDelay(on); } @Override public void setTrafficClass(int value) throws SocketException { delegate.setTrafficClass(value); } @Override public void shutdownInput() throws IOException { delegate.shutdownInput(); } @Override public void shutdownOutput() throws IOException { delegate.shutdownOutput(); } @Override public String toString() { return delegate.toString(); } @Override public boolean equals(Object o) { return delegate.equals(o); }}}在连接时像这样使用此类:
SSLContext sslcontext = SSLContext.getInstance("TLSv1"); sslcontext.init(null, null, null); SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory()); HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory); l_connection = (HttpsURLConnection) l_url.openConnection(); l_connection.connect();更新:
现在,正确的解决方案是使用Google Play服务安装更新的安全提供程序:
ProviderInstaller.installIfNeeded(getApplicationContext());
这有效地使您的应用程序可以访问较新版本的OpenSSL和Java安全提供程序,其中包括对SSLEngine中的TLSv1.2的支持。一旦安装了新的提供程序,就可以创建SSLEngine,以通常的方式支持SSLv3,TLSv1,TLSv1.1和TLSv1.2:
SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); SSLEngine engine = sslContext.createSSLEngine();或者,您可以使用来限制已启用的协议engine.setEnabledProtocols。
不要忘记添加以下依赖项(在此处找到最新版本):
compile 'com.google.android.gms:play-services-auth:11.8.0'
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)