从iOS应用到AWS Elastic Beanstalk后端的间歇性SSL错误

时间:2019-07-08 11:15:10

标签: ios amazon-web-services ssl amazon-elastic-beanstalk app-transport-security

我的iOS应用程序向后端发出HTTPS请求几个月以来,出现间歇性SSL错误。

错误说明:

An SSL error has occurred and a secure connection to the server cannot be made.

控制台在调试模式下记录日志:

2019-07-06 15:12:37.012198+0100 MyApp[37255:12499941] [BoringSSL] nw_protocol_boringssl_input_finished(1543) [C2.1:2][0x159e8e4a0] Peer disconnected during the middle of a handshake. Sending errSSLClosedNoNotify(-9816) alert
2019-07-06 15:12:37.026641+0100 MyApp[37255:12499941] TIC TCP Conn Failed [2:0x280486d00]: 3:-9816 Err(-9816)
2019-07-06 15:12:37.027759+0100 MyApp[37255:12499941] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9816)
2019-07-06 15:12:37.027839+0100 MyApp[37255:12499941] Task <D5AF17C0-C202-4229-BD52-690EFDB10379>.<1> HTTP load failed (error code: -1200 [3:-9816])
2019-07-06 15:12:37.028016+0100 MyApp[37255:12499941] Task <D5AF17C0-C202-4229-BD52-690EFDB10379>.<1> finished with error - code: -1200
2019-07-06 15:12:37.032759+0100 MyApp[37255:12500041] Task <D5AF17C0-C202-4229-BD52-690EFDB10379>.<1> load failed with error Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSErrorFailingURLStringKey=https://api.example.com/v1/example/example?param=example, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <D5AF17C0-C202-4229-BD52-690EFDB10379>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <D5AF17C0-C202-4229-BD52-690EFDB10379>.<1>"
), NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://api.example.com/v1/example/example?param=example, NSUnderlyingError=0x283ff2160 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9816, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9816}}, _kCFStreamErrorCodeKey=-9816} [-1200]

该错误主要发生在3G / 4G上,而不是wifi上,并且在网络信号较低时更经常发生。如果一旦发生,它将在接下来的几个请求中继续发生,但最终将在此后不久再次起作用。

基于分析,用户评论和用户错误报告:它影响很大一部分用户,但不是100%。

-

后端托管在AWS Elastic Beanstalk上。使用Nginx代理服务器以及负载均衡器后面的多个实例作为Docker应用程序。

我尝试增加和减小实例大小,但这似乎没有什么区别。

我最近从零开始创建了一个全新的Elastic Beanstalk环境,以查看是否有帮助。以前它使用的是经典负载均衡器,现在它使用的是应用程序负载均衡器。早期迹象表明它减少了SSL错误的数量,但仍在发生。

新的负载均衡器正在使用以下SSL策略:

ELBSecurityPolicy-FS-2018-06

其中定义如下: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html

是否应该使用其他SSL策略?

-

在应用程序中,Web请求是使用URLSession.shared.dataTask...等发出的。我还尝试使用Alamofire库来查看是否有所作为。没有。

我觉得这可能与Apple的App Transport Security有关。但是,由于它间歇性地失败,我对如何操作感到茫然。

相关的Apple文档在此页面的底部: https://developer.apple.com/security/

如果您需要更多信息来帮助调试,请告诉我。

-

如果您对可能导致问题的原因有任何想法,那么,我将非常感谢!

谢谢您的帮助!

5 个答案:

答案 0 :(得分:3)

免责声明: 这不是您的问题的答案,我只是想和您一起大声思考

这是我要检查的几点,认为这可能会帮助我确定问题的根本原因,前提是您拥有此信息或可以选择获取这些信息,否则除非您可以-用亚马逊调试

  • 很明显,这是证书固定问题

  • 通过Wiregark通过3g调制解调器检查TLS版本请求是否已发送,并检查来自AWS的要求,例如,它们可能需要1.2,而您正在发送1.1

  • 这对于在服务器端检查证书字符串并将其与客户端进行手动比较至关重要,因为它可能会通过连接管道进行不同的编码

  • ,只要您说它在连接速度慢时可能会更经常失败,请检查证书固定超时(服务器可能会获得证书字符串的一部分,并将其与它所拥有的证书字符串进行比较,并发现由于连接延迟)

  • 确保负载均衡器后面的docker应用的所有实例都具有与您固定的证书完全相同的版本

  • 检查连接失败的iOS版本的统计信息,并检查该特定版本中的安全性

答案 1 :(得分:1)

首先,我遇到了您描述的所有症状。在寻找解决方案时,网络团队,安全团队,软件团队等等。我与所有团队进行了交谈。这是一个很难解决的问题,但简要说明我们如何解决它会很有用。

提示1:如您所见,SSL身份验证并不总是错误的。有时它会抛出错误。 SSL密钥或基础结构中使用的任何文件最终都是带有字节的文件,有时会导致此错误,因为并非所有这些字节都可以在网络上发送。我认为,就我而言,甚至调试了这种情况。造成的文件包损坏。

提示2:对于不同的客户端,请求可以正常工作,有时无法正常工作的一般原因是服务器通过缓存响应某些请求。这通常与loadballancer配置有关。就我而言,基于cookie的身份验证已由软件工程师更改为其他身份验证模型。这样会通过ram中的静态对象扩展请求,从而导致字节传输出现问题,从而获得更好的性能。

我强烈建议这一点。在服务器端,应一一检查Loadballancer属性。查看生命周期管理。您甚至可以通过使Loadballancer变为基于会话或基于cookie的方式来更改身份验证方法,如果您确实需要的话。

答案 2 :(得分:1)

我对您的后端架构(docker,nginx)了解不多。我的猜测是,您的后端最初是为服务于非移动浏览器而编写的,是经过完全加密的内容,但是是在迁移到AWS之前编写的,并且后端认证吗?现在他们已经要求您为前端构建IOS应用,并将"lift and shift"后端集成到Elastic Beanstalk中?这是一个很好的策略,因为它更易于在云上运行,并且Elastic Beanstalk提供扩展功能。

此策略的问题在于,当原始后端加密流量达到负载平衡,并且加密会话未配置为在缩放后的后端之间正确浮动时,它可能会中断用户会话,并且会出现错误。

您有直觉创建一个新的Elastic Beanstalk应用程序并尝试应用程序负载平衡器的想法,但是我在AWS docs for configuring Load Balancing Elastic Beanstalk中发现了这一点,它可能与此矛盾:

  

与传统负载平衡器或网络负载平衡器不同,应用程序负载平衡器不能具有传输层(第4层)TCP或SSL / TLS侦听器。它仅支持HTTP和HTTPS侦听器。此外,它不能使用后端身份验证来验证负载均衡器和后端实例之间的HTTPS连接。

建议

要排除Elastic Beanstalk中的负载平衡,我将创建一个没有负载平衡的新Elastic Beanstalk环境(或非Elastic Beanstalk AWS计算堆栈),并查看在连接到客户端的情况下是否仍然遇到这些错误中的任何一个这个新环境。如果没有错误,那么您可以放心地告诉您的团队,他们需要考虑将身份验证从后端迁移到AWS服务中。

答案 3 :(得分:0)

您是否在Info.plist文件中添加了“应用传输安全设置”键?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSAllowsArbitraryLoadsForMedia</key>
    <true/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>YOUR_SERVER_COM</key>
        <dict>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
        <key>facebook.com</key>
        <dict>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
        <key>fbcdn.net</key>
        <dict>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
        <key>graph.facebook.com</key>
        <dict>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>
</plist>

答案 4 :(得分:0)

免责声明:我们找到了一种解决方案,但我不知道它是否适用于每种类型的负载均衡器。

我们遇到了同样的问题,经过2个月的研究(并得到了AWS支持的一点帮助),才找到了解决方案。

分析发送到服务器的数据包后,当请求具有IPv6地址的服务器 时,它会关闭TLS / SSL握手连接。

图扭曲:默认情况下,VPC负载平衡器不支持IPv6请求。 https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-internet-facing-load-balancers.html#internet-facing-ip-addresses

如文档所述,带有dualstack.前缀的Load Balancer DNS设置可以解析为IPv4 OR IPv6。因此,这里的解决方案是从负载均衡器DNS中删除此dualstack.部分,以便仅将其解析为IPv4。

其他情节的扭曲:您的Route 53设置对此并不在乎,仍然使您使用dualstack.前缀注册负载均衡器DNS。您甚至无法从设置地址的输入中删除此前缀(至少我们不能,每次模糊输入时,javascript都会添加它)。

因此,我们没有在Route 53中更改DNS,而是在指向我们的负载均衡器的Google Domains DNS配置条目中对其进行了更改。然后你去! 4G请求现在可以工作。

TL; DR:从域提供商中的负载均衡器DNS配置中删除dualstack.前缀。