gpt4 book ai didi

java - 如何在 android 中为 HttpsUrlConnection 禁用 SSLv3?

转载 作者:IT老高 更新时间:2023-10-28 23:26:38 25 4
gpt4 key购买 nike

我们在 android 中编写了客户端应用程序,它使用 HttpsUrlConnection API 与 https 服务器连接。由于 Poodle 漏洞,我们需要在调用任何请求时从启用的协议(protocol)列表中禁用 SSLv3。

我们关注 guidelines被预言机捕获

并在调用 url 连接之前添加以下行

java.lang.System.setProperty("https.protocols", "TLSv1");

此解决方案适用于普通的 java 程序。
当我们尝试连接仅适用于 SSLv3 协议(protocol)的服务器时,我们得到了 SSLHandShakeException

但担心的是:同样的修复不适用于 android。我是否遗漏了什么,或者我应该为 android 尝试另一种方法?请提出建议。

最佳答案

我通过使用wireshark分析数据包找到了解决方案。我发现,在建立安全连接时,android 从 TLSv1 回退到 SSLv3 。这是 android 版本 < 4.4 中的错误,可以通过从 Enabled Protocols 列表中删除 SSLv3 协议(protocol)来解决。我制作了一个名为 NoSSLv3SocketFactory.java 的自定义 socketFactory 类。用它来做一个socketfactory。

/*Copyright 2015 Bhavit Singh Sengar
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

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;
}

@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}

private Socket makeSocketSafe(Socket socket) {
if (socket instanceof SSLSocket) {
socket = new NoSSLv3SSLSocket((SSLSocket) socket);
}
return socket;
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port));
}

@Override
public 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 Services 安装更新的安全提供程序:

    ProviderInstaller.installIfNeeded(getApplicationContext());

这有效地使您的应用可以访问更新版本的 OpenSSL 和 Java 安全提供程序,其中包括对 SSLEngine 中的 TLSv1.2 的支持。安装新的提供程序后,您可以按照通常的方式创建支持 SSLv3、TLSv1、TLSv1.1 和 TLSv1.2 的 SSLEngine:

    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
SSLEngine engine = sslContext.createSSLEngine();

或者您可以使用 engine.setEnabledProtocols 限制启用的协议(protocol)。

不要忘记添加以下依赖项(latest version found here):

compile 'com.google.android.gms:play-services-auth:11.8.0'

欲了解更多信息,请查看 link .

关于java - 如何在 android 中为 HttpsUrlConnection 禁用 SSLv3?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26649389/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com