【问题标题】:XMPPFramework - Connect via SSL on OpenfireXMPPFramework - 在 Openfire 上通过 SSL 连接
【发布时间】:2014-08-09 12:54:45
【问题描述】:

我正在尝试通过 SSL 从我的 iOS XMPP 聊天客户端将我的用户连接到 Openfire 服务器。

在我的 iOS 客户端中:

- (void)setupStream 
{
    ...
    // BOOL values for security settings
    customCertEvaluation = NO;
    allowSelfSignedCertificates = YES;
    allowSSLHostNameMismatch = NO;
}

在我的 Openfire 服务器的 Security Settings > Client Connection Security 中,我设置了:

Required - Clients can only connect to the server using secured connections.

因此,将调用以下委托方法:

- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings 
{
    NSString *expectedCertName = [xmppStream.myJID domain];

    if (customCertEvaluation)
        [settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];

    if (allowSelfSignedCertificates)
        [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];

    if (allowSSLHostNameMismatch)
        [settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];

    else
        if (expectedCertName)
            [settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}

我从这个帖子尝试了这个解决方案:XMPPFramework TLS/SSL connection with Openfire

但是,当我运行我的应用程序并尝试连接到服务器时,我会收到以下错误:

Security option unavailable - kCFStreamSSLAllowsAnyRoot - You must use manual trust evaluation

我查看了GCDAsyncSocket 类并意识到kCFStreamSSLAllowsAnyRoot 被声明为已弃用。实施了一个 NSAssert 来故意抛出错误。

接下来,我决定更改我的 BOOL 值:

- (void)setupStream 
{
    ...
    // BOOL values for security settings
    // Manually evaluate trust
    customCertEvaluation = YES;
    allowSelfSignedCertificates = NO;
    allowSSLHostNameMismatch = NO;
}

这一次,再次无法与服务器建立连接,但没有提示错误。

如果我将客户端连接安全更改回原始设置,我可以很好地连接到 Openfire > 可选。但是,我不会通过 SSL 连接,如客户端会话中每个用户状态旁边的 lock 图标所示。

我的 Android 客户端(使用 Smack API for XMPP)通过 SSL 连接到 Openfire 没有问题。所以我想知道是否有我必须使用 XMPPFramework 为我的 iOS 客户端实现的解决方法。

如果有任何建议,我将不胜感激。

【问题讨论】:

    标签: ios ssl xmpp openfire xmppframework


    【解决方案1】:

    您正在尝试使用过时的 API,请查看 iPhoneXMPP 示例以获取新的 - https://github.com/robbiehanson/XMPPFramework/commit/73f3c35a930b91d27e62bc19e91d9cdcc02c6e42

    【讨论】:

    • 不,我使用的是最新的 API。这就是我不推荐使用kCFStreamSSLAllowsAnyRoot 的原因。旧 API,特别是在四月之前仍然使用它。相反,我在上面的问题中使用了旧的解决方案。我阅读了 XMPPFramework Github 中的问题页面 - 在引入对 SSL Pinning 的支持后,自 4 月 22 日起不再支持旧的 Apple 弃用方法。请参阅 github.com/robbiehanson/XMPPFramework/issues/333。无论如何,我已经制定了解决方案。完成更多测试后将在此处分享。
    【解决方案2】:
    customCertEvaluation = YES;
    allowSelfSignedCertificates = YES;
    allowSSLHostNameMismatch = NO;  
    

    试试这些可能会有帮助

    【讨论】:

    • 请解释为什么这个“可能有帮助”。
    • 因为它对我有用!!! .可能是没有建立连接的原因是因为allowSelfSignedCertifates函数应该设置为yes,只有这样才允许证书用于签署安全连接。试试这个,试一试没有错。
    • @v1shnu.mee 您很可能使用过时的 API。因为您的 allowSelfSignedCertificates 的相应方法已被弃用。看看我上面的答案。
    • @KeithOYS 你能解释一下证书是如何创建的以及它是如何传输的。我们如何查看连接是否安全。
    • @v1shnu.mee 请参阅:创建自签名服务器证书 - igniterealtime.org/builds/openfire/docs/latest/documentation/… |如果用户通过 SSL 连接,您会在“会话”页面中的用户名旁边看到一个锁定图标。
    【解决方案3】:

    说明

    在最新版本的 XMPP (after April 22) 中,您可以不再allowSelfSignedCertificates = YES 与以下内容一起使用:

    if (allowSelfSignedCertificates)
        [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];`
    

    这是因为 kCFStreamSSLAllowsAnyRootSSLSetAllowsAnyRoot 已被弃用。

     /* 
      * ==== The following UNAVAILABLE KEYS are: (with throw an exception)
      * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE)
      *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
      *     Corresponding deprecated method: SSLSetAllowsAnyRoot
      */
    

    XMPPFramework/GCDAsyncSocket.h & Deprecated Secure Transport Functions


    解决方案

    1. 转到 Openfire 服务器 > 安全设置 > 客户端连接安全

      Check: Required - Clients can only connect to the server using secured connections.

    2. 在 AppDelegate 中定义变量

      BOOL customCertEvaluation;
      
    3. 在 setupStream 中设置变量

      - (void)setupStream 
      {
          ...
          customCertEvaluation = YES;
      }
      
    4. 在 willSecureWithSettings 中设置安全设置

      - (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
      {
          /*
           * Properly secure your connection by setting kCFStreamSSLPeerName 
           * to your server domain name
           */
          [settings setObject:xmppStream.myJID.domain forKey:(NSString *)kCFStreamSSLPeerName];
      
          /*
           * Use manual trust evaluation
           * as stated in the XMPPFramework/GCDAsyncSocket code documentation
           */
          if (customCertEvaluation)
              [settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];
      }
      
    5. 手动验证对等体

      /*
       * This is only called if the stream is secured with settings that include:
       * - GCDAsyncSocketManuallyEvaluateTrust == YES
       * That is, if a delegate implements xmppStream:willSecureWithSettings:, and plugs in that key/value pair.
       */
       - (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
       {
           /* Custom validation for your certificate on server should be performed */
      
           completionHandler(YES); // After this line, SSL connection will be established
       }
      

    【讨论】:

      【解决方案4】:

      我在更新 XMPPFramework 后遇到了同样的问题。经过几天试图找出问题所在,我遇到了这个问题,但该解决方案对我不起作用。

      这对我有用。问题似乎源于您的 xmppStream.startTLSPolicy。明确设置 startTLSPolicy 对我有用。

      xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicyPreferred; // or
      xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicyRequired;
      

      这里解释了它的工作原理。

      在 XMPPStream 的 handleStreamFeatures 方法中,事实证明是这样的。如果您的 XMPP 服务器没有将 starttls 作为“必需”返回,并且您没有明确设置 startTLSPolicy(default=XMPPStreamStartTLSPolicyAllowed)。客户端只会进行普通连接,而不是 TLS 连接。

      这是 XMPPStream 中进行检查的代码部分(供参考)。

      /**
       * This method is called anytime we receive the server's stream features.
       * This method looks at the stream features, and handles any requirements so communication can continue.
      **/
      - (void)handleStreamFeatures
      {
          NSAssert(dispatch_get_specific(xmppQueueTag), @"Invoked on incorrect queue");
      
          XMPPLogTrace();
      
          // Extract the stream features
          NSXMLElement *features = [rootElement elementForName:@"stream:features"];
      
          // Check to see if TLS is required
          // Don't forget about that NSXMLElement bug you reported to apple (xmlns is required or element won't be found)
          NSXMLElement *f_starttls = [features elementForName:@"starttls" xmlns:@"urn:ietf:params:xml:ns:xmpp-tls"];
      
          if (f_starttls)
          {
              if ([f_starttls elementForName:@"required"] || [self startTLSPolicy] >= XMPPStreamStartTLSPolicyPreferred)
              {
                  // TLS is required for this connection
      
                  // Update state
                  state = STATE_XMPP_STARTTLS_1;
      
                  // Send the startTLS XML request
                  [self sendStartTLSRequest];
      
                  // We do not mark the stream as secure yet.
                  // We're waiting to receive the <proceed/> response from the
                  // server before we actually start the TLS handshake.
      
                  // We're already listening for the response...
                  return;
              }
          }
          else if (![self isSecure] && [self startTLSPolicy] == XMPPStreamStartTLSPolicyRequired)
          {
              // We must abort the connection as the server doesn't support our requirements.
      
              NSString *errMsg = @"The server does not support startTLS. And the startTLSPolicy is Required.";
              NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
      
              otherError = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamUnsupportedAction userInfo:info];
      
              // Close the TCP connection.
              [self disconnect];
      
              // The socketDidDisconnect:withError: method will handle everything else
              return;
          }
      
          // Check to see if resource binding is required
          // Don't forget about that NSXMLElement bug you reported to apple (xmlns is required or element won't be found)
          NSXMLElement *f_bind = [features elementForName:@"bind" xmlns:@"urn:ietf:params:xml:ns:xmpp-bind"];
      
          if (f_bind)
          {
              // Start the binding process
              [self startBinding];
      
              // We're already listening for the response...
              return;
          }
      
          // It looks like all has gone well, and the connection should be ready to use now
          state = STATE_XMPP_CONNECTED;
      
          if (![self isAuthenticated])
          {
              [self setupKeepAliveTimer];
      
              // Notify delegates
              [multicastDelegate xmppStreamDidConnect:self];
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-07-26
        • 2017-01-02
        • 1970-01-01
        • 2012-05-05
        • 2012-04-24
        • 2015-05-31
        • 1970-01-01
        • 2015-01-01
        相关资源
        最近更新 更多