4

摘要:Salesforce.com 最近为其沙箱实例 (test.salesforce.com) 禁用了 TLSv1,并且只能支持 TLSv1.1 及更高版本的入站和出站请求的 API 集成。

我正在使用带有 JDK 7.0 的 Java Axis1.0 客户端代码(通过 webservice soap)连接到 salesforce.com。我收到异常“UNSUPPORTED_CLIENT:此组织中已禁用 TLS 1.0。使用 https 连接到 Salesforce 时请使用 TLS 1.1 或更高版本。” With Java7.0 Supported Protocols:SSLv2Hello, SSLv3, TLSv1, TLSv1.1, TLSv1.2 Enabled Protocols: TLSv1

`使用 Java8.0 当我尝试使用 java8 客户端连接到 salesforce.com 时,连接成功。

支持的协议:SSLv2Hello、SSLv3、TLSv1、TLSv1.1、TLSv1.2 启用协议:TLSv1、TLSv1.1、TLSv1.2`

我必须使用 Java 7,因为我们的应用程序正在使用它。我尝试设置 vm args: -Dhttps.protocols=TLSv1.1,TLSv1.2 -Ddeployment.security.SSLv2Hello=false -Ddeployment.security.SSLv3=false -Ddeployment.security.TLSv1=false -Ddeployment.security.TLSv1.1 =true -Ddeployment.security.TLSv1.2=true" 但没有成功。

你能帮我找出 Java7 中的设置以启用 TLSv1.1 吗?

4

3 回答 3

5

找到了解决方案:

我必须编写自定义 JSSESocketFactory(因为我使用的是 Java webservice Axis1.0 客户端)和 AxisProperties 设置。

就像是,

public class TLSSocketSecureFactory extends JSSESocketFactory {

private final String TLS_VERSION_1_1 = "TLSv1.1";
private final String TLS_VERSION_1_2 = "TLSv1.2";

public TLSSocketSecureFactory(@SuppressWarnings("rawtypes") Hashtable attributes) {
super(attributes);
}

@Override
protected void initFactory() throws IOException {
SSLContext context;
try {
  context = SSLContext.getInstance(TLS_VERSION_1_1);
  context.init(null, null, null);
  sslFactory = context.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
  //printstacktrace or throw IOException
}
}

@Override
public Socket create(String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL) throws Exception {
if (sslFactory == null) {
  initFactory();
}
Socket s = super.create(host, port, otherHeaders, useFullURL);
((SSLSocket) s).setEnabledProtocols(new String[] {TLS_VERSION_1_1, TLS_VERSION_1_2 });
return s;
}
}

AxisProperties.setProperty("axis.socketSecureFactory",TLSSocketSecureFactory.class.getCanonicalName());

这仅对 JDK7 是必需的。当应用程序迁移到JDK8时,不需要这个类。在 Java8 中,TLSv1.1 和 TLS1.2 默认启用。

注意:在服务器上设置 VM 配置对 Axis java 客户端没有帮助。

于 2016-07-02T00:29:31.680 回答
2

来自Salesforce 文档

Java 7:使用 HttpsURLConnection 的 https.protocols Java 系统属性启用 TLS 1.1 和 TLS 1.2。要在非 HttpsURLConnection 连接上启用 TLS 1.1 和 TLS 1.2,请在应用程序源代码中创建的 SSLSocket 和 SSLEngine 实例上设置启用的协议。

于 2016-07-01T07:42:25.403 回答
2

当 Axis 传输是默认的 HTTPSender 时,上述解决方案运行良好。此外,知道新的套接字工厂不仅可以用 AxisProperties 替换,还可以用系统属性替换,这很有用,它可以像这样在命令行上传递:

-Dorg.apache.axis.components.net.SecureSocketFactory=your.package.TLSv12JSSESocketFactory

这是我的 TLSv12JSSESocketFactory 的代码:

package your.package;

import java.util.Hashtable;
import java.io.IOException;
import java.net.Socket;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import org.apache.axis.components.net.JSSESocketFactory;
import org.apache.axis.components.net.BooleanHolder;

public class TLSv12JSSESocketFactory extends JSSESocketFactory {

    private final String TLS_VERSION_1_2 = "TLSv1.2";

    public TLSv12JSSESocketFactory( @SuppressWarnings("rawtypes") Hashtable attributes ) {
        super(attributes);
    }

    @Override
    protected void initFactory() throws IOException {
        SSLContext context;
        try {
            context = SSLContext.getInstance( TLS_VERSION_1_2 );
            context.init( null, null, null );
            sslFactory = context.getSocketFactory();
        } catch ( Exception e ) {
            throw new IOException( "Could not init SSL factory with TLS context: " + TLS_VERSION_1_2, e );
        }
    }

    @Override
    public Socket create( String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL ) throws Exception {

        Socket s = super.create( host, port, otherHeaders, useFullURL );
        ((SSLSocket) s).setEnabledProtocols( new String[] { TLS_VERSION_1_2 } );

        return s;
    }
}

在我的情况下,我必须使用 Apache Commons HttpClient 作为传输来更改 Axis 1.4。这涉及创建一个实现接口 SecureProtocolSocketFactory 的类。这是我的代码:

package your.package;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;


public class TLSv12HttpsSocketFactory implements SecureProtocolSocketFactory
{
    private static final String TLS_VERSION_1_2 = "TLSv1.2";
    private final SecureProtocolSocketFactory base;

    public TLSv12HttpsSocketFactory( ProtocolSocketFactory base )
    {
        if ( base == null || !(base instanceof SecureProtocolSocketFactory) ) throw new IllegalArgumentException();
        this.base = (SecureProtocolSocketFactory) base;
    }

    private Socket acceptOnlyTLS12( Socket socket )
    {
        if ( socket != null && (socket instanceof SSLSocket) ) {
            ((SSLSocket) socket).setEnabledProtocols( new String[] { TLS_VERSION_1_2 } );
        }

        return socket;
    }

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

    @Override
    public Socket createSocket( String host, int port, InetAddress localAddress, int localPort ) throws IOException
    {
        return acceptOnlyTLS12( base.createSocket(host, port, localAddress, localPort) );
    }

    @Override
    public Socket createSocket( String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params ) throws IOException
    {
        return acceptOnlyTLS12( base.createSocket(host, port, localAddress, localPort, params) );
    }

    @Override
    public Socket createSocket( Socket socket, String host, int port, boolean autoClose ) throws IOException
    {
        return acceptOnlyTLS12( base.createSocket(socket, host, port, autoClose) );
    }
}

但我还必须像这样修改 org.apache.axis.transport.http.CommonsHTTPSender 类(编译时生成一些类文件):

// import the new socket factory
import your.package.TLSv12HttpsSocketFactory;
...
// add this at the end of the initialize() method
// setup to our custom TLSv1.2 socket factory
String scheme = "https";
Protocol baseHttps = Protocol.getProtocol( scheme );
int defaultPort = baseHttps.getDefaultPort();

ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory();
ProtocolSocketFactory customFactory = new TLSv12HttpsSocketFactory( baseFactory );

Protocol customHttps = new Protocol( scheme, customFactory, defaultPort );
Protocol.registerProtocol( scheme, customHttps );
于 2018-02-07T18:57:44.770 回答