Java 要为SSL套接字启用哪些密码套件?

Java 要为SSL套接字启用哪些密码套件?,java,ssl,encryption,Java,Ssl,Encryption,我正在使用Java的SSLSocket保护客户端和服务器程序之间的通信。服务器程序还提供来自web浏览器的HTTPS请求 根据第371页的“”,您应该始终在SSLSocket/SSLServerSocket上调用setenablediphersuites,以确保最终协商的密码套件对于您的目的来说足够强大 也就是说,调用我的SSLSocketFactory的getDefaultCipherSuite方法可以产生大约180个选项。这些选项范围从TLS\u RSA\u WITH_AES\u 256\u

我正在使用Java的SSLSocket保护客户端和服务器程序之间的通信。服务器程序还提供来自web浏览器的HTTPS请求

根据第371页的“”,您应该始终在
SSLSocket
/
SSLServerSocket
上调用
setenablediphersuites
,以确保最终协商的密码套件对于您的目的来说足够强大


也就是说,调用我的
SSLSocketFactory
getDefaultCipherSuite
方法可以产生大约180个选项。这些选项范围从
TLS\u RSA\u WITH_AES\u 256\u CBC\u SHA
(我认为这相当安全)到
SSL\u RSA\u WITH_RC4\u 128\u MD5
(鉴于MD5的当前状态,不太确定这是否安全)到
SSL\u DHE\u DSS\u EXPORT\u WITH_DES40\u CBC\u SHA
(不完全确定这是什么)

限制套接字的密码套件的合理列表是什么?


请注意,客户端和服务器可以访问服务提供商,并且它们可能安装或不安装无限加密策略文件。

不要在其中使用任何带有导出的内容。这是由于对强加密技术的出口限制造成的

编辑:更改为使用2009文档

2009年NIST列出了以下内容,包括TLS_RSA_与_AES_256_CBC_SHA(如您所述):

TLS_RSA_WITH_NULL_SHA(除非您确定不需要任何隐私/机密性,否则不要使用此选项)


下面是我用来执行密码套件和协议的Java类。在
SSLSocketFactoryEx
之前,我在访问
SSLSocket
时正在修改属性。堆栈溢出上的Java人员提供了帮助,所以能够在这里发布它很好


SSLSocketFactoryEx
更喜欢更强的密码套件(如
ECDHE
DHE
),它省略了较弱和受损的密码套件(如
RC4
MD5
)。当TLS 1.2不可用时,它必须启用四个RSA密钥传输密码,以便与Google和Microsoft进行互操作。他们是
TLS\u RSA\u WITH_AES\u 256\u CBC\u SHA256
TLS\u RSA\u WITH_AES\u 256\u CBC\u SHA
和两个朋友。如果可能,您应该删除
TLS\u RSA.*
密钥传输方案

使密码套件列表尽可能小。如果你公布所有可用的密码(类似于Flaschen的列表),那么你的列表将是80+。这在
ClientHello
中占用了160个字节,并且可能会导致一些设备出现故障,因为它们有一个小的、固定大小的缓冲区来处理
ClientHello
。损坏的设备包括F5和Ironport

实际上,当首选列表与Java支持的密码套件相交时,下面代码中的列表将被分成10或15个密码套件。例如,以下是我在准备使用无限JCE策略连接或连接microsoft.com或google.com时得到的列表:

  • TLS_ECDHE_ECDSA_与_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_与_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_与_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_与_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_与_AES_256_GCM_SHA384
  • TLS_DHE_DSS_与AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_与_AES_128_GCM_SHA256
  • TLS_DHE_DSS_与AES_128_GCM_SHA256
  • TLS_DHE_DSS_与AES_256_CBC_SHA256
  • TLS_DHE_RSA_与_AES_128_CBC_SHA
  • TLS_DHE_DSS_与_AES_128_CBC_SHA
  • TLS_RSA_与_AES_256_CBC_SHA256
  • TLS_RSA_与_AES_256_CBC_SHA
  • TLS_RSA_与_AES_128_CBC_SHA256
  • TLS_RSA_与_AES_128_CBC_SHA
该列表省略了弱/受损的算法,如RC4和MD5。如果启用了它们,那么您可能会偶尔收到一封电子邮件

使用默认JCE策略时,列表将更小,因为该策略将删除AES-256和其他一些。我想大概有7套密码套件有限制政策

SSLSocketFactoryEx
类还确保使用TLS 1.0及更高版本的协议。Java8之前的Java客户端禁用TLS1.1和1.2
SSLContext.getInstance(“TLS”)
也将潜入
SSLv3
(即使在Java8中),因此必须采取步骤删除它

最后,下面的类是TLS1.3感知的,因此当提供者提供它们时,它应该可以工作。如果可用,
*\u CHACHA20\u POLY1305
密码套件是首选,因为它们比当前的一些套件快得多,并且具有更好的安全特性。谷歌已经在其服务器上推出了它。我不确定甲骨文什么时候会提供。OpenSSL将为他们提供OpenSSL 1.0.2

您可以这样使用它:

URL url = new URL("https://www.google.com:443");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

SSLSocketFactoryEx factory = new SSLSocketFactoryEx();
connection.setSSLSocketFactory(factory);
connection.setRequestProperty("charset", "utf-8");

InputStream input = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(input, "utf-8");
BufferedReader buffer = new BufferedReader(reader);
...

类SSLSocketFactoryEx扩展了SSLSocketFactory
{
public SSLSocketFactoryEx()抛出NoSuchAlgorithmException、KeyManagementException
{
initSSLSocketFactoryEx(null,null,null);
}
公共SSLSocketFactoryEx(KeyManager[]km,TrustManager[]tm,SecureRandom random)抛出NoSuchAlgorithmException,KeyManagementException
{
初始SSLSocketFactoryEx(km,tm,随机);
}
公共SSLSocketFactoryEx(SSLContext ctx)抛出NoSuchAlgorithmException、KeyManagementException
{
initSSLSocketFactoryEx(ctx);
}
公共字符串[]GetDefaultCipherSuite()
{
返回m_密码;
}
公共字符串[]GetSupportedCipherSuite()
{
返回m_密码;
}
公共字符串[]getDefaultProtocols()
{
返回m_协议;
}
公共字符串[]getSupportedProtocols()
{
返回m_协议;
}
公共套接字createSocket(套接字、字符串主机、int端口、布尔自动关闭)引发IOException
{
SSLSocketFactory=m_ctx.getSocketFactory();
SSLSocket ss=(SSLSocket)factory.createSocket(s、主机、端口、自动关闭);
ss.可设置的协议(m_协议);
ss.可设置的iPhone套件(m_密码);
返回ss
URL url = new URL("https://www.google.com:443");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

SSLSocketFactoryEx factory = new SSLSocketFactoryEx();
connection.setSSLSocketFactory(factory);
connection.setRequestProperty("charset", "utf-8");

InputStream input = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(input, "utf-8");
BufferedReader buffer = new BufferedReader(reader);
...
class SSLSocketFactoryEx extends SSLSocketFactory
{
    public SSLSocketFactoryEx() throws NoSuchAlgorithmException, KeyManagementException
    {
        initSSLSocketFactoryEx(null,null,null);
    }

    public SSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random) throws NoSuchAlgorithmException, KeyManagementException
    {
        initSSLSocketFactoryEx(km, tm, random);
    }

    public SSLSocketFactoryEx(SSLContext ctx) throws NoSuchAlgorithmException, KeyManagementException
    {
        initSSLSocketFactoryEx(ctx);
    }

    public String[] getDefaultCipherSuites()
    {
        return m_ciphers;
    }

    public String[] getSupportedCipherSuites()
    {
        return m_ciphers;
    }

    public String[] getDefaultProtocols()
    {
        return m_protocols;
    }

    public String[] getSupportedProtocols()
    {
        return m_protocols;
    }

    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException
    {
        SSLSocketFactory factory = m_ctx.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(s, host, port, autoClose);

        ss.setEnabledProtocols(m_protocols);
        ss.setEnabledCipherSuites(m_ciphers);

        return ss;
    }

    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
    {
        SSLSocketFactory factory = m_ctx.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(address, port, localAddress, localPort);

        ss.setEnabledProtocols(m_protocols);
        ss.setEnabledCipherSuites(m_ciphers);

        return ss;
    }

    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException
    {
        SSLSocketFactory factory = m_ctx.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(host, port, localHost, localPort);

        ss.setEnabledProtocols(m_protocols);
        ss.setEnabledCipherSuites(m_ciphers);

        return ss;
    }

    public Socket createSocket(InetAddress host, int port) throws IOException
    {
        SSLSocketFactory factory = m_ctx.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(host, port);

        ss.setEnabledProtocols(m_protocols);
        ss.setEnabledCipherSuites(m_ciphers);

        return ss;
    }

    public Socket createSocket(String host, int port) throws IOException
    {
        SSLSocketFactory factory = m_ctx.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(host, port);

        ss.setEnabledProtocols(m_protocols);
        ss.setEnabledCipherSuites(m_ciphers);

        return ss;
    }

    private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)
    throws NoSuchAlgorithmException, KeyManagementException
    {
        m_ctx = SSLContext.getInstance("TLS");
        m_ctx.init(km, tm, random);

        m_protocols = GetProtocolList();
        m_ciphers = GetCipherList();
    }

    private void initSSLSocketFactoryEx(SSLContext ctx)
    throws NoSuchAlgorithmException, KeyManagementException
    {
        m_ctx = ctx;

        m_protocols = GetProtocolList();
        m_ciphers = GetCipherList();
    }

    protected String[] GetProtocolList()
    {
        String[] preferredProtocols = { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" };
        String[] availableProtocols = null;

        SSLSocket socket = null;

        try
        {
            SSLSocketFactory factory = m_ctx.getSocketFactory();
            socket = (SSLSocket)factory.createSocket();

            availableProtocols = socket.getSupportedProtocols();
            Arrays.sort(availableProtocols);
        }
        catch(Exception e)
        {
            return new String[]{ "TLSv1" };
        }
        finally
        {
            if(socket != null)
                socket.close();
        }

        List<String> aa = new ArrayList<String>();
        for(int i = 0; i < preferredProtocols.length; i++)
        {
            int idx = Arrays.binarySearch(availableProtocols, preferredProtocols[i]);
            if(idx >= 0)
                aa.add(preferredProtocols[i]);
        }

        return aa.toArray(new String[0]);
    }

    protected String[] GetCipherList()
    {
        String[] preferredCiphers = {

            // *_CHACHA20_POLY1305 are 3x to 4x faster than existing cipher suites.
            //   http://googleonlinesecurity.blogspot.com/2014/04/speeding-up-and-strengthening-https.html
            // Use them if available. Normative names can be found at (TLS spec depends on IPSec spec):
            //   http://tools.ietf.org/html/draft-nir-ipsecme-chacha20-poly1305-01
            //   http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-02
            "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
            "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
            "TLS_ECDHE_ECDSA_WITH_CHACHA20_SHA",
            "TLS_ECDHE_RSA_WITH_CHACHA20_SHA",

            "TLS_DHE_RSA_WITH_CHACHA20_POLY1305",
            "TLS_RSA_WITH_CHACHA20_POLY1305",
            "TLS_DHE_RSA_WITH_CHACHA20_SHA",
            "TLS_RSA_WITH_CHACHA20_SHA",

            // Done with bleeding edge, back to TLS v1.2 and below
            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",

            "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
            "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
            "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",

            // TLS v1.0 (with some SSLv3 interop)
            "TLS_DHE_RSA_WITH_AES_256_CBC_SHA384",
            "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
            "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
            "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",

            "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
            "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",
            "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",

            // RSA key transport sucks, but they are needed as a fallback.
            // For example, microsoft.com fails under all versions of TLS
            // if they are not included. If only TLS 1.0 is available at
            // the client, then google.com will fail too. TLS v1.3 is
            // trying to deprecate them, so it will be interesteng to see
            // what happens.
            "TLS_RSA_WITH_AES_256_CBC_SHA256",
            "TLS_RSA_WITH_AES_256_CBC_SHA",
            "TLS_RSA_WITH_AES_128_CBC_SHA256",
            "TLS_RSA_WITH_AES_128_CBC_SHA"
        };

        String[] availableCiphers = null;

        try
        {
            SSLSocketFactory factory = m_ctx.getSocketFactory();
            availableCiphers = factory.getSupportedCipherSuites();
            Arrays.sort(availableCiphers);
        }
        catch(Exception e)
        {
            return new String[] {
                "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
                "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
                "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
                "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
                "TLS_RSA_WITH_AES_256_CBC_SHA256",
                "TLS_RSA_WITH_AES_256_CBC_SHA",
                "TLS_RSA_WITH_AES_128_CBC_SHA256",
                "TLS_RSA_WITH_AES_128_CBC_SHA",
                "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
            };
        }

        List<String> aa = new ArrayList<String>();
        for(int i = 0; i < preferredCiphers.length; i++)
        {
            int idx = Arrays.binarySearch(availableCiphers, preferredCiphers[i]);
            if(idx >= 0)
                aa.add(preferredCiphers[i]);
        }

        aa.add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV");

        return aa.toArray(new String[0]);
    }

    private SSLContext m_ctx;

    private String[] m_ciphers;
    private String[] m_protocols;
}