iOS 损坏发送到服务器的 TLS 数据

Posted

技术标签:

【中文标题】iOS 损坏发送到服务器的 TLS 数据【英文标题】:iOS corrupts TLS data sent to server 【发布时间】:2012-06-30 03:16:04 【问题描述】:

我在 ios 上使用 SocketRocket 或 Unitt Web 套接字库来执行安全 Web 套接字时遇到了同样的问题。我可以控制 Java Web 套接字服务器 - Netty - 并且可以详细观察服务器端 SSL/TLS 数据。我使用端口 6970 作为套接字。

使用 TLS 握手正确打开客户端 wss 套接字后,我在第一次写入客户端数据时收到服务器错误,即 Web 套接字握手。客户端写入 202 字节,服务器接收 272 字节,服务器端消息验证码失败。我在服务器跟踪中看到我的客户端数据,但它有 8 个字节的垃圾预置。

首先我在服务器上尝试了具有相同结果的 SocketRocket 库 - 良好的握手后 MAC 错误。我的 Unitt 客户端的 android 版本运行良好。我的 javascript 安全 Web 套接字代码也很好用。

在 iOS / XCode 上,我可以调试 Unitt/AsyncSocket/doSendBytes 中的 CFWriteStreamWrite(...) - 它报告确实写入了 202 个客户端数据字节。但我不知道如何进一步调试。在某个地方,iOS TLS 框架在发送过程中破坏了我的客户端数据——我想。

【问题讨论】:

你确定它没有通过某种方式被网络损坏吗? 没有。但这很容易检查。我将在我的开发 Mac 上安装 Charles 代理来拦截 TCP 数据包。我希望看到 Charles 报告的相同错误,因为它是用 Java 编写的,并且使用了我的服务器应用程序使用的某种代码。 Charles 代理对我的 6970 端口不起作用,所以我安装了 Wireshark 并观察到,虽然我的应用程序写入了 202 字节,但本地网络接口传输了 277 字节。我看不到在哪里可以获得适用于我的 Mac OS 版本 10.7.3 的调试库。 假设确实存在 Mac OS 库错误,我将尝试为 wss:// 使用端口 443 而不是 6970,如果这不起作用,我将尝试为 ws 使用端口 80: //。问题是我必须以 root 身份运行我的服务器应用程序或使用 iptables 才能使用端口 80 或 443 - 这需要一些工作。 【参考方案1】:

通过过滤掉某些与 iOS 不兼容的椭圆曲线密码套件,我能够让我的 iOS 安全 Web 套接字与我的 Java Netty 服务器一起运行。这是我的代码...

/** the enabled SSL cipher suites */
private static String[] enabledCipherSuites;
/** the enabled SSL cipher suites lock */
private static final Object ENABLED_CIPHER_SUITES_LOCK = new Object();
/** the iOS incompatible cipher suites */
private static final List<String> iOSIncompatibleCipherSuites = new ArrayList<>();

/** Configures the SSL engine for client or for the server. Arranges the enabled ciphers to favor the
* most secure over the less secure, and omits the least secure ciphers.  Requires that the SSL server
* authenticate the client.
*
* @param sslEngine the SSL engine
* @param useClientMode the indicator whether the SSL engine is operating in client mode
* @param needClientAuth the indicator whether the server authenticates the client's SSL certificate
*/
public static synchronized void configureSSLEngine(
         final SSLEngine sslEngine,
         final boolean useClientMode,
         final boolean needClientAuth) 
  //Preconditions
  assert sslEngine != null : "sslEngine must not be null";

  if (useClientMode) 
    LOGGER.info("configuring SSL engine for the client side of the connection");
    sslEngine.setUseClientMode(true);
    sslEngine.setNeedClientAuth(false);
   else 
    if (needClientAuth) 
      LOGGER.info("configuring SSL engine for the server side of the connection with required client authorization");
     else 
      LOGGER.info("configuring SSL engine for the server side of the connection without required client authorization");
    
    sslEngine.setUseClientMode(false);
    sslEngine.setNeedClientAuth(needClientAuth);
 
  synchronized (ENABLED_CIPHER_SUITES_LOCK) 
    if (enabledCipherSuites == null) 
      iOSIncompatibleCipherSuites.add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384");
      iOSIncompatibleCipherSuites.add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256");
      iOSIncompatibleCipherSuites.add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
      iOSIncompatibleCipherSuites.add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");

      // TLS_ECDHE_RSA_WITH_RC4_128_SHA is the negotiated cipher suite for iOS

      // select and arrange the highest security cipher suites and cache the result
      final String[] supportedCipherSuites = sslEngine.getSupportedCipherSuites();
      final List<String> enabledCipherSuitesList = new ArrayList<>(supportedCipherSuites.length);
      // The first pass selects 256 bit ciphers available with the Java Cryptography Extension (JCE)
      // Unlimited Strength Jurisdiction Policy Files, downloaded and installed from http://java.sun.com/javase/downloads/index.jsp .
      for (final String supportedCipherSuite : supportedCipherSuites) 
        if (supportedCipherSuite.contains("_256_") && !supportedCipherSuite.contains("_anon_")) 
          enabledCipherSuitesList.add(supportedCipherSuite);
        
      
      // The second pass selects 128 bit ciphers that use SHA hashing - its more secure than MD5 but slower.
      for (final String supportedCipherSuite : supportedCipherSuites) 
        if (supportedCipherSuite.contains("_128_") && !supportedCipherSuite.endsWith("_MD5") && !supportedCipherSuite.contains("_anon_")) 
          enabledCipherSuitesList.add(supportedCipherSuite);
        
      
      // The third pass selects 128 bit ciphers that use MD5 hashing.
      for (final String supportedCipherSuite : supportedCipherSuites) 
        if (supportedCipherSuite.contains("_128_") && supportedCipherSuite.endsWith("_MD5") && !supportedCipherSuite.contains("_anon_")) 
          enabledCipherSuitesList.add(supportedCipherSuite);
       
      
      // The fourth pass removes the iOS incompatible cipher suites
      enabledCipherSuitesList.removeAll(iOSIncompatibleCipherSuites);

      if (LOGGER.isDebugEnabled()) 
        LOGGER.debug("enabledCipherSuites: " + enabledCipherSuitesList);
      
      final int enabledCipherSuitesList_size = enabledCipherSuitesList.size();
      enabledCipherSuites = new String[enabledCipherSuitesList_size];
      for (int i = 0; i < enabledCipherSuitesList_size; i++) 
        enabledCipherSuites[i] = enabledCipherSuitesList.get(i);
      
    
    sslEngine.setEnabledCipherSuites(enabledCipherSuites);
  

【讨论】:

以上是关于iOS 损坏发送到服务器的 TLS 数据的主要内容,如果未能解决你的问题,请参考以下文章

发送邮件功能

System.IO.Exception:管道在客户端损坏

iOS 9改用HTTPS,适配HTTP

如何使用 SYSLOG 和 TLS 从 Windows 服务发送日志?

我使用ionic 2开发cordova项目将base64发送到服务器图像已损坏

Windows 2008 R2 服务器上的 CURL 损坏