推送系列二:流程及其安全性

2017-01-14 10:46:12来源:http://www.jianshu.com/p/4f3732cc3a94作者:杭研融合通信iOS人点击

第七城市


Paste_Image.png
引言

我们日常使用的大多数app几乎第一次启动都会弹出一堆权限获取的alert交互框,这类alert会阻塞用户的使用进程,所以很多用户为了快速使用app,都会随便地点击其中任一按钮以便快速过渡这个状态,这样其实很容易陷入app的一些“黑洞”中,比如某些app对摄像头权限的获取,可能在不经意间打开用户手机的摄像头获取到隐私信息;某些app对通讯录权限的获取,可能会将个人信息泄露;而与我们本文相关的推送相关的权限,app可能在以下方面对用户有所影响:


可能有频繁的及时消息弹出框
可能有偶尔的广告弹出框

本文不会讲述如何避开这些“黑洞”, 而是讲述“黑洞”之一----推送,因为推送对用户体验如此大的影响,iOS系统制定了一套严密的机制, 本文对实现流程进行介绍的同时,着重讲解其中对安全性的考虑: 简单来说就是,首先保证只有认证的开发者的app可以推送,其他人无法通过手段干扰此app的推送操作,其次必须用户许可才能接受推送,并且用户可以随时取消推送通知。


流程

下面首先介绍推送实现的流程,如下图:




技术上我们可以简化为:




上面的流程包含:


建立安全通道;
注册服务,请求token:app通过APNs提供的api,向iOS系统注册推送服务,系统将请求转发给APNs服务器,服务器将device token反馈给iOS设备,通过APNs提供的api传给app;
app将获取到的token上传给自己的服务器
当存在需要推送的消息时,自己的服务器将消息内容、提醒形式、token等信息发送给APNs服务器;
APNs服务器根据需要推送消息的token,获取到token对应的设备是否在线,如果设备在线,则将消息推送给设备,由系统将推送消息通过定义的形式展示或者提示出来。
注意:

当设备由于无网络等情况不在线时,app中与网络相关服务将无法使用,推送也无法到达,因为APNs也是基于网络的长连接来实现,苹果针对这种情况了也提供了保障机制,当离线期间有很多推送时,虽然苹果无法将消息及时推送到指定设备上,但也会基于体验考虑做一定处理,具体可参考官方文档。


流程中的安全性

下面将逐步论证苹果在每个步骤的具体过程和安全机制:


针对第一个步骤:建立安全通道

具体如下图:




Trust between APNs and each device is established automatically by the device’s operating system upon initial device activation (and without participation by your app), as described in this section.


需要强调的是,上图中的过程在iOS设备激活的时刻就已经开始进行,是与app本身无关的,是iOS设备本身与APNs服务器之间的沟通建立信任的过程。当这个信任确定成功后,后续这个iOS设备上所有app与APNs服务器之间的沟通都是安全可靠的。
(可参考 https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1)


流程中包含四次交互--四次握手:


iOS设备在刚激活时将首先向APNs服务器打招呼--请求tls连接,也就是说建立一个基于tls协议的长连接(这种连接可以在保证双发的身份可信的情况下,对连接后续的通信过程进行加密,保证通信信息的安全保密性。)
APNs服务器收到请求后,将反馈给iOS设备一个APNs服务器的证书;
iOS设备收到证书后验证通过,将反馈给APNs服务器自己的证书和私钥,二者都是设备激活过程中获得并存在设备的钥匙串中的(并非apple开发者网站上建立的证书)。
APNs服务器接收到后,通过发来的证书和私钥验证连接可靠,握手成功。
针对第二个步骤:注册服务,请求token

第一步建立安全连接后,当app中调用注册推送服务的方法时,需要调用APNs的api:
registerForRemoteNotificationTypes
来注册,APNs服务器首先根据app的bundle id生成一个只跟此app有关的device token,然后将device token加密后发送给设备,设备通过ios系统转发给指定app,app会通过相应的代理方法
applicationdidRegisterForRemoteNotificationsWithDeviceToken
来得知已经注册成功并返回加密后的device token。
通过上面的分析可知,即使device token被第三方截获,也无法模拟用户与APNs服务器进行通信来伪造用户,因为身份验证无法通过,APNs服务器不会信任这个第三方。


注意:

app每次launch必须重新注册推送服务,重新获取device token,因为device token会发生变化,如果APNs服务器存储的不是最新的device token,推送将失败。(device token是个迷,欲了解device token可以参考我的另一篇博文:)


针对第三个步骤:app发送device token给自己的服务器

这一步是需要开发者自己来保证安全的一步,一般我们可以模拟苹果的机制,对device token进行对称加密,或者与服务器协商好撒盐和md5的方式,保证通信过程中即使被截获也无法被破解。当然为了提高安全级别,可以加入认证授权的操作,甚至模仿苹果的tls方式来进一步保证安全性。


针对第四个步骤:provider发送消息给APNs服务器

这一步安全性通常有两种方式来保证:
第一种是经典的做法,也是与设备和APNs服务器相同的做法,即通过建立tls长连接来校验身份,四次握手后开始发送消息。与第一步差别在于第三次握手时传给APNs服务器的apple开发者网站注册的推送证书和私钥。这样APNs服务器可以通过证书判断当前通过信的对方是可信的服务器,连接建立成功,provider便可以给PNs服务器发送推送消息,要求其转发。 如下图:




第二种做法是从iOS9开始苹果推荐的更简便的http2的方式,从下图的这个过程可以看出是对四次握手的改良,我们的服务器第二次握手收到APNs服务器的推送证书后,就已经建立可以信任的连接,后面推送消息将通过基于http2的请求来实现:每次推送的请求都携带者经过我们自己服务器私钥加密过的token,APNs服务器收到请求后首先验证token是否合法,如果合法则证明是可信任的服务器,则将反馈一个成功的response给我们的服务器。连接建立成功,provider便可以给PNs服务器发送推送消息,要求其转发。




这一步,provider的请求中header中存放着device token,便于APNs服务器了解这条推送的目的地是哪里。


针对第五个步骤:APNs服务器推送消息到设备

这一步的安全性其实是基于上面注册推送服务时已经建立好的基于tls协议的长连接,这时APNs服务器根据provider的请求中device token使用秘钥解码得到设备的id和app的bundle id, 这样通过设备的id 判断这个设备在线并且可以信任,直接将推送消息发给设备上的对应的app,app中可以通过api来获取到最新一条推送的内容:
didReceiveRemoteNotification 或 applicationdidFinishLaunchingWithOptions
第二个接口对应app已经挂起后用户点击推送的消息弹窗后的响应。


这样,承载着信鸽功能一样的推送就路由到了用户的手机上,给用户一个提示---赶紧去app中查看吧。



Paste_Image.png

但是设备如果不在线呢?
关于这种情况,官方说法是有一种QoS保障: 当设备不在线时,如果收到很多条推送,只保留最后一条推送一定时间,如果超时则舍弃。


Apple Push Notification service includes a default Quality of Service (QoS) component that performs a store-and-forward function. If APNs attempts to deliver a notification and the destination device is offline, APNs stores the notification for a limited period of time and delivers it when the device becomes available again. This component stores only the most recent notification per device and per app. If a device is offline, sending a new notification causes the previous notification to be discarded. If a device remains offline for a long time, all stored notifications are discarded.


我通过微信进行了验证,当手机切到飞行模式后,好友给我连续发10条信息,当我回到正常模式后,只收到最后一条推送。(注意:由于APNs是长连接服务,APNs通过心跳来判断ios设备是否在线,由于我们不知道心跳间隔,当手机刚切入到飞行模式时就发送消息,实际可能会收到10条推送,因为此时APNs判断ios设备还在线,所以不会启动QoS保障,所以验证时请在切入飞行模式1分钟以后)


苹果对推送的建议是不要使用推送作为通信的直接载体,而是作为一种通知形式:


Because the delivery of remote notifications is not guaranteed, never include sensitive data or data that can be retrieved by other means in your payload. Instead, use notifications to alert the user to new information or as a signal that your app has data waiting for it. For example, an email app could use remote notifications to badge the app’s icon or to alert the user that new email is available in a specific account, as opposed to sending the contents of email messages directly. Upon receiving the notification, the app should open a direct connection to your email server to retrieve the email messages.




第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台