使用自签名证书在 iOS 9 中发出 HTTPS 请求 [关闭]

2023-11-20

我想使用自签名证书向自定义服务器发出 HTTPS 请求。我正在使用 NSURLConnection 类并处理身份验证质询,但总是在控制台中收到错误消息:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

然后方法“connection:didFailWithError:”被调用并出现以下错误:

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x150094100>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=<CFArray 0x1500ddd90 [0x19f6dab68]>{type = immutable, count = 1, values = (
    0 : <cert(0x14e6fb370) s: (server certificate name) i: (custom CA name)>
)}, NSUnderlyingError=0x1504ae170 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSErrorFailingURLStringKey=https://217.92.80.156:9090/(method name and parameters), NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x1500ddd90 [0x19f6dab68]>{type = immutable, count = 1, values = (
    0 : <cert(0x14e6fb370) s: (server certificate name) i: (custom CA name)>
)}, _kCFStreamPropertySSLClientCertificateState=2, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x150094100>, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., _kCFStreamPropertySSLClientCertificates=<CFArray 0x14e5ee8e0 [0x19f6dab68]>{type = mutable-small, count = 2, values = (
    0 : <SecIdentityRef: 0x15012cd40>
    1 : <cert(0x15014aa70) s: (client certificate name) i: (custom CA name)>
)}, _kCFStreamErrorDomainKey=3, NSErrorFailingURLKey=https://217.92.80.156:9090/(method name and parameters), _kCFStreamErrorCodeKey=-9802}}, NSErrorClientCertificateChainKey=<CFArray 0x14e5ee8e0 [0x19f6dab68]>{type = mutable-small, count = 2, values = (
    0 : <SecIdentityRef: 0x15012cd40>
    1 : <cert(0x15014aa70) s: (client certificate name) i: (custom CA name)>
)}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://217.92.80.156:9090/(method name and parameters), NSErrorFailingURLStringKey=https://217.92.80.156:9090/(method name and parameters), NSErrorClientCertificateStateKey=2}

应用程序收到两个身份验证质询(NSURLAuthenticationMethodClientCertificate 和 NSURLAuthenticationMethodServerTrust)并按以下方式处理它们:

- (void) connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if(challenge.proposedCredential && !challenge.error)
    {
        [challenge.sender useCredential:challenge.proposedCredential forAuthenticationChallenge:challenge];

        return;
    }

    NSString *strAuthenticationMethod = challenge.protectionSpace.authenticationMethod;
    NSLog(@"authentication method: %@", strAuthenticationMethod);

    NSURLCredential *credential = nil;
    if([strAuthenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate])
    {
        // get identity and certificate from p.12
        NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]];

        NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"password" forKey:(__bridge id)kSecImportExportPassphrase];
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        OSStatus securityError = SecPKCS12Import((__bridge CFDataRef)PKCS12Data,(__bridge CFDictionaryRef)optionsDictionary, &items);

        SecIdentityRef identity = NULL;
        SecCertificateRef certificate = NULL;
        if(securityError == errSecSuccess)
        { 
            CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
            identity = (SecIdentityRef)CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);

            CFArrayRef array = (CFArrayRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemCertChain);
            certificate = (SecCertificateRef)CFArrayGetValueAtIndex(array, 0);
        }

        credential = [NSURLCredential credentialWithIdentity:identity certificates:[NSArray arrayWithObject:(__bridge id)(certificate)] persistence:NSURLCredentialPersistenceNone];

        CFRelease(items);
    }
    else if([strAuthenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {       
        int trustCertificateCount = (int)SecTrustGetCertificateCount(challenge.protectionSpace.serverTrust);
        NSMutableArray *trustCertificates = [[NSMutableArray alloc] initWithCapacity:trustCertificateCount];
        for(int i = 0; i < trustCertificateCount; i ++)
        {
            SecCertificateRef trustCertificate =  SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, i);
            [trustCertificates addObject:(__bridge id) trustCertificate];
        }            

        SecPolicyRef policyRef = NULL;
        policyRef = SecPolicyCreateSSL(YES, (__bridge CFStringRef) challenge.protectionSpace.host);

        SecTrustRef trustRef = NULL;
        if(policyRef)
        {
            SecTrustCreateWithCertificates((__bridge CFArrayRef) trustCertificates, policyRef, &trustRef);
            CFRelease(policyRef);
        }

        if(trustRef)
        {
//          SecTrustSetAnchorCertificates(trustRef, (__bridge CFArrayRef) [NSArray array]);
//          SecTrustSetAnchorCertificatesOnly(trustRef, NO);

            SecTrustResultType result;
            OSStatus trustEvalStatus = SecTrustEvaluate(trustRef, &result);
            if(trustEvalStatus == errSecSuccess)
            {
                // just temporary attempt to make it working.
                // i hope, there is no such problem, when we have final working version of certificates.
                if(result == kSecTrustResultRecoverableTrustFailure)
                {
                    CFDataRef errDataRef = SecTrustCopyExceptions(trustRef);
                    SecTrustSetExceptions(trustRef, errDataRef);

                    SecTrustEvaluate(trustRef, &result);
                }

                if(result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)
                    credential = [NSURLCredential credentialForTrust:trustRef];
            }

            CFRelease(trustRef);
        }
    }
    else
    {
        DDLogWarn(@"Unexpected authentication method. Cancelling authentication ...");
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }

    if(credential)
        [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
    else
        [challenge.sender cancelAuthenticationChallenge:challenge];
}

在 CFNetwork 诊断日志中,我可以看到握手程序即将启动。至少应用程序发送“ClientHello”消息,然后服务器发送其“ServerHello”消息并要求进行身份验证。这里应用程序尝试发送身份验证响应,但立即收到错误。 (同时,在服务器日志中我根本没有看到任何有关握手的消息)。这是诊断日志的一部分:

Sep 15 10:51:49  AppName[331] <Notice>: CFNetwork Diagnostics [3:49] 10:51:49.185 {
    Authentication Challenge
       Loader: <CFURLRequest 0x1501931c0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0}
    Challenge: challenge space https://217.92.80.156:9090/, ServerTrustEvaluationRequested (Hash f9810ad8165b3620)
    } [3:49]
Sep 15 10:51:49  AppName[331] <Notice>: CFNetwork Diagnostics [3:50] 10:51:49.189 {
    Use Credential
        Loader: <CFURLRequest 0x1501931c0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0}
    Credential: Name: server, Persistence: session
    } [3:50]
Sep 15 10:51:49  AppName[331] <Notice>: CFNetwork Diagnostics [3:51] 10:51:49.190 {
     touchConnection
              Loader: <CFURLRequest 0x1501931c0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0}
    Timeout Interval: 60.000 seconds
    } [3:51]
Sep 15 10:51:49  AppName[331] <Notice>: CFNetwork Diagnostics [3:52] 10:51:49.192 {
    Response Error
    Request: <CFURLRequest 0x14e5d02a0 [0x19f6dab68]> {url = https://217.92.80.156:9090/(method name and parameters), cs = 0x0}
      Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFNetworkCFStreamSSLErrorOriginalValue=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x1500ddd90 [0x19f6dab68]>{type = immutable, count = 1, values = (
                0 : <cert(0x14e6fb370) s: (server certificate name) i: (custom CA name)>
             )}, _kCFStreamPropertySSLClientCertificateState=2, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x150094100>, _kCFStreamPropertySSLClientCertificates=<CFArray 0x14e5ee8e0 [0x19f6dab68]>{type = mutable-small, count = 2, values = (
                0 : <SecIdentityRef: 0x15012cd40>
                1 : <cert(0x15014aa70) s: (client certificate name) i: (custom CA name)>
             )}, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802}
    } [3:52]

我们的后端实例可以安装在客户端,因此我无法在 Info.plist 文件中设置任何域异常。此外,应用程序可以通过 IPv4 形式的 IP 地址请求服务器,但不能通过域名(如我的示例中所示)。

我尝试过什么:

  • 使用 NSURLSession 而不是 NSURLConnection,但没有任何成功;
  • 检查了 Apple 对服务器实施的 ATS 要求here(后端开发人员确信他的实现满足所有这些要求);
  • 根据 stackoverflow 和 Apple 开发者论坛中已解决的各种问题,设置用于信任验证的锚证书;
  • 特别关注similar帖子及其相关内容solution在开发者论坛上;

我正在使用 iOS 9 GM Seed(Build 13A340)和 xCode 7 GM Seed(Build 7A218)在 iPad Air 2 上测试 https 请求。重要提示:此功能在 iOS 8 上运行良好。考虑到这一点,我可能会认为问题出在我们的服务器中,但我们的后端开发人员向我保证一切都很好。

现在我没有主意了。如果有人能给我一个提示,或者至少建议一些其他诊断,这将揭示特定的错误,比“致命警报”更具体,我将不胜感激。

Thanks.

编辑1:SecTrustEvaluate总是返回kSecTrustResultRecoverableTrustFailure,这就是为什么我必须找到某种解决方法。


根据这个:https://forums.developer.apple.com/message/36842#36842

修复 HTTP 加载失败(kCFStreamErrorDomainSSL,-9802)的最佳方法是在 info.plist 文件中设置异常,如下所示:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>test.testdomain.com</key>
    <dict>
      <key>NSIncludesSubdomains</key>
      <true/>
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
    </dict>
  </dict>
</dict>

重要的一点是,这并不比 iOS8 更安全,只是不如 iOS9 支持的完整 ATS 安全。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用自签名证书在 iOS 9 中发出 HTTPS 请求 [关闭] 的相关文章

  • i识别人的扫描图像中的眼睛

    我想开发一个 iPhone 应用程序 它应该识别 QR 阅读器扫描的图像中人的眼睛 脸部和肤色 如何在图像中检测眼睛 虽然这可能是可能的 但我只是警告您 无论编程如何 它都会有一定程度的不准确性 任何面部 视网膜检测软件都可能被欺骗 并且考
  • Firebase 分析在 DebugView 中显示不正确的数据

    我正在使用 Firebase 分析 我注册了两个用户属性 并且有两个自定义事件 每个事件包含 3 到 50 个不同的选项 我遇到的问题是 当我设置用户属性时 DebugView 通常会显示事件的旧用户属性或根本不显示 有时它可以正常工作 请
  • RestoreCompletedTransactions() 没有调用 paymentQueue UpdatedTransactions?

    我在 Swift 4 iOS 11 中恢复 IAP 时遇到问题 我的AppDelegate实施SKPaymentTransactionObserver In AppDelegate s didFinishLaunchingWithOptio
  • 上传时防止空闲状态(iOS 上的 Web 应用程序)

    我正在构建一个将在移动和桌面上使用的网络应用程序 在 iOS 上进行测试后 我注意到我的手机将进入空闲状态 屏幕关闭 返回时显示锁定屏幕 即使有是一个正在上传的文件 ajax上传 有什么办法可以防止这种情况发生吗 我正在通过将应用程序作为
  • Xcode 6 具有 Swift 超慢打字和自动完成功能

    是只有我还是 Xcode 6 6 0 1 with Swift 似乎是超级慢当您键入代码时 尤其是使用自动完成功能时 一个普通的 Objective C 类 即使在 Swift 项目中 工作原理也几乎和以前一样 所以是 Swift 杀死了它
  • sqlite+fmdbvacuum命令后内存泄漏(?)

    我通过 FMDB 包装器在我的应用程序中使用 sqlite 在调用 VACUUM 之前 我的应用程序中的内存使用量为 2 25 MB myFmdb executeUpdate VACUUM 后记是 5 8 MB 我似乎无法回收内存 真空后
  • 如何在 MKMapView iOS 中显示多个注释?

    我是 iOS 开发新手 我想在 iOS 中的 MKMapViewController 中显示多个注释 为此我在 viewDidLoad 方法中编写了代码 void viewDidLoad super viewDidLoad self map
  • iOS 8 选项卡栏项目背景颜色

    上周我一直在努力寻找解决方案 但在尝试了我能找到或想到的所有可能的解决方案后 我没有运气 我发现并尝试过的每个解决方案要么不起作用 要么已经过时 我有 5 个UITabBarItem s in a UITabBar放置在UITabBarCo
  • 什么是“响应 backboardd 的终止而终止”?

    我在滑块的帮助下使用一段代码在视图上添加阴影 滑块设置为 15 到 15 此代码在以下情况下效果很棒slider value为正 但如果为负 应用程序将停止工作 崩溃日志很奇怪Terminating in response to backb
  • 如何更改导航栏上 BarButtonItem 的文本?

    我正在尝试创建一个可以编辑的项目列表 像这样的东西 为此 我在视图顶部添加了一个导航栏 然后在 XCode 设计器中添加了 2 个栏按钮项 我将左侧按钮的标识符设置为 添加 将右侧按钮的标识符设置为 编辑 当我单击 编辑 时 我想将文本更改
  • 像 peek and pop 一样手动振动 iPhone 6S?

    如何手动触发类似单击的振动 就像使用 peek pop 或应用程序快捷方式时发生的振动一样 这个方法很容易实现 而且效果非常好 我自己尝试过 import AudioToolbox AudioServicesPlaySystemSound
  • 如何才能运行性能测试十次以上?

    默认情况下 Xcode 性能测试会运行十次 我的结果是这十次测试的平均值 问题是每次运行时平均结果变化很大 因此我必须运行测试至少五次才能获得收敛结果 这既乏味又耗时 有没有办法配置 XCode 或单元测试本身运行十次以上 XCTestCa
  • iOS Swift:谷歌登录错误

    我正在关注this https developers google com identity sign in ios sign in ver swift before you begin使用 swift 在我的 iOS 应用程序中添加 go
  • 了解 ibeacon 距离

    尝试掌握 ibeacon 信标 低功耗蓝牙 BLE 如何保持距离的基本概念 有没有关于 ibeacon 到底能测量多远的真实文档 假设我在 300 英尺外 ibeacon 是否有可能检测到这一点 专门针对 v4 v5 和 iOS 但通常是任
  • 如何重试基于块的 URL 请求

    我正在使用 iOS7 的新 URL 请求方法获取数据 如下所示 NSMutableURLRequest request NSMutableURLRequest requestWithURL NSURL URLWithString self
  • RestKit:如何获取简单的 JSON 字符串数组?

    我应该如何使用 RestKit 来获取像这样的 JSON 字符串数组 Paris London Brussels New York 我尝试进行对象映射 但由于没有关键路径或属性 我不知道要映射什么 我什至不需要映射 结果可能只是一个数组或字
  • 是否可以使用 Firebase 云消息传递 (FCM) 直接从设备将 PushNotifications 发送到特殊 UDID?

    我正在考虑将所有注册 ID 推送令牌 保留在数据库中并从 iPhone 向用户发送通知 我尝试了类似的操作 但没有收到任何通知 func sendPNMessage FIRMessaging messaging sendMessage bo
  • UIScrollView 在 addSubview 或更改框架后出现不必要的滚动

    我有一个UIScrollView充满子视图 创建它并最初填充它时一切都很好 但是 当我添加位于可见屏幕部分之外的新子视图时 或者当我只是调整也在可见屏幕部分之外的现有子视图的大小时 会出现随后的 0 3 秒长的滚动动画 我可以看到它 发生在
  • 如何在 iOS 7 中将 CSV 文件关联到我的应用程序

    今天是个好日子 我逐行遵循这两个教程 尝试将我的应用程序关联到 csv 文件 电子邮件应用程序附件 但是在我将这些更改添加到我的应用程序的 plist 文件中之后 然后构建我的应用程序并在我的设备 iPhone 4 iOS 7 0 4 没有
  • 导航回 ViewController 时出现重复消息问题

    我有一个 ViewController 它向用户显示更多信息 然后他们单击一个按钮 它将它们发送到我的 messageView 它是一个 JSQ ViewController JSQViewController 使用集合视图类 当用户导航回

随机推荐

  • 在elasticsearch中使用现有字段作为id

    今天刚开始使用elasticSearch 我想知道是否可以设置某种全局参数以始终使用文档中的某个字段作为 ID 我的 JSON 文档将始终拥有自己的唯一 ID Record ID a06b0000004SWbdAAG System Mods
  • Java 和本地数据库

    TL 博士 需要一些 Java 帮助来连接到真正的本地数据库 无法访问服务器技术 或者如果您可以编写代码 那就可以了 它所要做的就是查询数据库 MS Access 尽管可以更改 并输出一个 JSON 字符串 有关更多具体信息 请参阅 EDI
  • React Native android APK 扩展支持吗?

    我尝试搜索 React Native Android APK Expansion 但找不到任何有关它的页面 RN 支持 APK 扩展文件吗 如何在本地开发中测试它 谢谢 None
  • 在spring data elasticsearch中,聚合查询不能放在存储库实现中吗?

    我第一次使用 spring boot elasticsearch 我现在已经弄清楚如何使用 elastics java api 描述我的串行差异管道查询 正如您将在下面看到的 这个查询相当大 并且为每个对象返回多个存储桶以及每个存储桶之间的
  • 丢失密钥对后访问 EC2 实例

    几个月前 我启动了一个 EC2 实例 当时我将 pem 密钥存储在我的 PC 中 电脑崩溃后 我不得不在上面重新安装 Windows 而且我没有 pem 文件的备份 有什么方法可以让我到达 EC2 实例上的提示符 任何通过 ssh 或其他方
  • ASP.Net MVC 控制器构造函数中的会话为 null

    为什么控制器的构造函数中Session为null 可以从 Action 方法访问它 据推测 因为 MVC 路由框架负责更新控制器 所以它此时还没有 重新 实例化会话 有谁知道这是否是设计使然 如果是 为什么 我已经通过使用延迟加载模式设法规
  • jackson xml 列出了识别为重复键的反序列化

    我正在尝试使用将 xml 转换为 jsonjackson 2 5 1 and jackson dataformat xml 2 5 1xml结构是从Web服务器接收的并且未知 因此我不能用java类来表示该对象 并且我试图直接转换为Tree
  • 莫西忽略场

    使用 moshi 序列化为 json 字符串时是否有一种简单的方法来忽略字段 我只能想到是一个自定义适配器 但我感觉有更好的方法 Use transient关于现场声明 private transient String your varia
  • 使用反射在内部类中实例化带有参数的构造函数

    我有一些类似的事情 object parameter new object 1 parameter 0 x object instantiatedType Activator CreateInstance typeToInstantiate
  • OpenCV - 让滑块在视频播放期间更新其位置

    我选择了 学习 OpenCV 并尝试了一些代码示例 练习 在此代码片段中 我想让滑块随着每个视频帧的变化而更新其位置 但由于某种原因它不起作用 图片通过以下代码冻结 include cv h include highgui h int g
  • 在 SELECT INTO 中保留 ORDER BY

    我有一个 T SQL 查询 它从一个表中获取数据并将其复制到一个新表中 但只复制满足特定条件的行 SELECT VibeFGEvents INTO VibeFGEventsAfterStudyStart FROM VibeFGEvents
  • 检查路径是否有效

    我只是想知道 我正在寻找一种方法来验证给定路径是否有效 注意 我不想检查文件是否存在 我只想证明路径的有效性 所以如果文件可能存在于该位置 问题是 我在 Net API 中找不到任何内容 由于 Windows 支持多种格式和位置 我宁愿使用
  • 为什么 x 在内部作用域中未定义? [复制]

    这个问题在这里已经有答案了 在下面的代码中 var x 1 function console log x var x 2 为什么console log x 时 x未定义 可变提升 实际的代码是这样执行的 var x 1 function v
  • Interface Builder > Inspector > Bindings 中的“控制器键”是什么意思?

    我在文档中找不到他们解释所有这些字段及其含义的地方 尤其是 控制器键 我不清楚 复印我在另一个问题上的回答 控制器键是您要绑定的 控制器对象的属性 的键 模型关键路径是绑定对象可以向模型对象请求更基本的对象 例如字符串或图像 或其他模型对象
  • 使用 gson 将 json 字段反序列化为纯字符串

    我正在尝试将 json 对象反序列化为 java bean 我面临的主要问题是我想对待这个领域object将 json 字符串视为普通字符串 即使它包含可能正确的 json 对象 json结构是这样的 type user object id
  • REPL 和解释器有什么区别?

    REPL 和解释器之间有技术差异吗 交互式解释器使用 REPL 不需要配备口译员 例如 您可以以非交互模式 在文件上 运行 Python 并且它不会使用读取 评估 打印循环
  • 使用 numpy fft 提取相位信息

    我正在尝试使用快速傅立叶变换来提取单个正弦函数的相移 我知道 在纸面上 如果我们将函数的变换表示为 T 那么我们有以下关系 然而 我发现虽然我能够准确捕获余弦波的频率 但除非我以极高的速率采样 否则相位不准确 例如 import numpy
  • 如何在 Windows 机器上使用 nginx 运行 django?

    我有一个 Django 项目 我已经安装了nginx服务器 我想在 Windows 机器上运行 nginx 和 django 我尝试过几个博客Nginx Django Uwsgi 但它们都需要 uwsgi 但 uwsgi 未安装在 Wind
  • 代码生成器、ORM、存储过程

    这些软件架构在哪些领域表现出色或失败 哪些关键要求会促使您选择其中一个 请假设您有可用的开发人员 他们可以完成良好的面向对象代码以及良好的数据库开发 另外 请避免圣战 所有三种技术都有优点和缺点 我感兴趣的是最适合在哪里使用哪种技术 这些工
  • 使用自签名证书在 iOS 9 中发出 HTTPS 请求 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 目前不接受答案 我想使用自签名证书向自定义服务器发出 HTTPS 请求 我正在使用 NSURLConnection 类并处理身份验证质询 但总是在控制台中收到错误消息 NSURLSessio