iOS开发高级分享 - iOS上的设备标识符和指纹
苹果认可的标识符
Apple提供了各种API,以方便用户识别各种用途:
通用标识符(UDID)
在iOS的早期,苹果公司提供了一个uniqueIdentifier财产上UIDevice-亲切地称为udid (不要与UUID混淆)。虽然这样的功能在今天看来是不可想象的,但该属性一直存在到IOS 5,直到它被废弃并被替换为identifierForVendor在iOS 6中。
供应商标识符(IDFV)
从IOS 6开始,开发人员可以使用identifierForVendor财产上UIDevice若要生成在同一供应商创建的应用程序和扩展之间共享的唯一标识符(idfv).
- import UIKit
- let idfv = UIDevice.current.identifierForVendor // BD43813E-CFC5-4EEB-ABE2-94562A6E76CA
根据文献 identifierForVendor回归nil“在重新启动设备之后,但在用户解锁设备之前。”目前还不清楚什么时候会出现这种情况,但是如果你的应用程序在后台做了什么事情,一定要记住一些事情。
广告标识符(IDFA)
连同identifierForVendor引进了一种新的行政支助框架,这是苹果创建的,以帮助区分应用程序功能所需的识别功能与任何服务于广告的东西。
结果advertisingidentifier财产(亲切地称为idfa(由其同伙)不同于identifierForVendor通过为每个人返回相同的值。值可以更改,例如,如果用户重置广告标识符或者抹去他们的设备。
- import AdSupport
- let idfa = ASIdentifierManager.shared().advertisingIdentifier
如果广告跟踪受到限制,则该属性将返回一个归零UUID。
- idfa.uuidString == "00000000-0000-0000-0000-000000000000" // true if the user has limited ad tracking
奇怪的是,MacOS Mojave引入了一个clearAdvertisingIdentifier()方法,它似乎会创建一个“公地悲剧”在这种情况下,一个应用程序可能会破坏其他人的利益。(从用户的角度来看,这不是一件坏事!)
还有一个奇怪的例子isAdvertisingTrackingEnabled财产。根据文献:
在执行任何广告跟踪之前,请检查此属性的值。如果值为false,则只将广告标识符用于以下目的:频率限制、属性、转换事件、估计唯一用户的数量、广告欺诈检测和调试。
这种“荣誉制度”方法遵从性令人困惑。这让你想知道是什么用法不会属于这些广泛的津贴范围之内。
如果你对这件事的警力有任何洞察力,给我们一条线-我们想听更多.
DeviceCheck
identifierForVendor和advertisingIdentifier提供与uniqueIdentifier属性在IOS 6中替换,只有一个例外:能够在设备重置和应用程序卸载过程中持久化。
在iOS 11中,苹果悄悄地推出了DeviceCheck框架,它允许开发人员分配由Apple持久化的两位信息直到开发人员手动删除.
任何熟悉DeviceCheck框架的人都应该熟悉与DeviceCheck框架的交互APN在App Store Connect和您的服务器上设置设备之后,客户端在设备上生成令牌,这些令牌被发送到服务器以设置或查询两位信息:
- import DeviceCheck
- let device = DCDevice.current
- if device.isSupported {
- device.generateToken { data, error in
- if let token = data?.base64EncodedString() {
- send token to your server
- }
- }
- }
基于设备令牌和客户端发送的其他信息,服务器告诉Apple通过发送如下JSON有效负载来设置每个位值:
- {
- "device_token": "QTk4QkFDNEItNTBDMy00Qjc5LThBRUEtMDQ5RTQzRjNGQzU0Cg==",
- "transaction_id": "D98BA630-E225-4A2F-AFEC-BE3A3D591708",
- ,
- "bit0": true,
- "bit1": false
- }
为了在稍后的时间点检索这两位,服务器发送一个没有bit0和bit1字段:
- {
- "device_token": "QTk4QkFDNEItNTBDMy00Qjc5LThBRUEtMDQ5RTQzRjNGQzU0Cg==",
- "transaction_id": "D98BA630-E225-4A2F-AFEC-BE3A3D591708",
- }
如果一切正常,苹果的服务器将以200状态代码和以下JSON有效负载:
- {
- "bit0" : true
- "bit1" : false,
- "last_update_time" : "2019-10"
- }
据称,苹果创建了DeviceCheck框架,以满足优步在限制滥用促销代码方面的需求。虽然DeviceCheck支持存储只两位信息(例如,足以确定设备是否曾被用于创建帐户以及设备是否与欺诈活动相关联),我们(诚然是模糊的)担心时间戳,即使是截断,也可能被用来存储两位以上的信息。
今日iOS的指纹图谱
尽管苹果提供了这些服务,但广告商仍在继续努力规避用户隐私保护,并利用他们掌握的所有信息,以其他方式识别用户。
多年来,苹果对设备硬件信息的访问受到限制,已安装的应用程序, 附近WiFi网络...他们要求应用程序请求许可才能获得您当前的位置,访问您的相机和麦克风,浏览您的联系人,并找到并连接到蓝牙附件。他们采取了大胆的步骤防止Safari中的用户跟踪.
由于缺乏这方面的信息,公司不得不发挥创造力,从现有信息的残余物中提炼出独特的身份。这种由外部因素组合而成的识别过程称为指印.
不幸的现实是,我们可以通过微不足道的少量信息得到独特的识别。例如,一个群体中的个体最多可以被四个时间戳坐标所挑选出来。(de Montjoye,Hidalgo,Verleysen,&Blondel,2013年)或者仅仅是生日和邮政编码(Sweeney,2000年).
自2012年以来,每个WWDC都举办了一次关于隐私的会议,但唯一特别提到指纹的是2014年的简短讨论如何避免这样做。
根据我们的计算,坚定的一方可以使用传统的、不受限制的API来产生几十个随机性:
地区信息(~36位)
地区信息是在苹果平台上识别信息的最大来源。你喜欢的语言、区域、日历、时区的组合,以及你安装的键盘很大程度上说明了你是谁--尤其是在你没有那么传统的偏好的情况下。
- import Foundation
- Locale.current.languageCode
- log2(Double(Locale.isoLanguageCodes.count)) // 9.217 bits
- Locale.current.regionCode
- log2(Double(Locale.isoRegionCodes.count)) // 8 bits
- Locale.current.calendar.identifier
- // ~2^4 (16) Calendars
- TimeZone.current.identifier
- log2(Double(TimeZone.knownTimeZoneIdentifiers.count)) // 8.775 bits
- UserDefaults.standard.object(forKey: "AppleKeyboards")// ~2^6 (64) iOS keyboards
我们最近推特关于可以不受限制地访问表情符号键盘信息的应用程序。从那时起,我们就被告知苹果公司正在调查这一问题。
可访问性(~10位)
可访问性首选项还提供了大量的信息,每个单独的设置都贡献了一个潜在的比特:
- UIAccessibility.isBoldTextEnabled
- UIAccessibility.isShakeToUndoEnabled
- UIAccessibility.isReduceMotionEnabled
- UIAccessibility.isDarkerSystemColorsEnabled
- UIAccessibility.isReduceTransparencyEnabled
- UIAccessibility.isAssistiveTouchRunning
约25%的用户利用动态类型通过配置首选字体大小,该选择还可用于指纹:
- let application = UIApplication.shared
- application.preferredContentSizeCategory
硬件信息(~5或~6位)
尽管这些年来,操作系统更新中大多数最活跃的比特都被锁定了,但仍然有足够多的比特用于识别。
在IOS上,您可以获得用户设备的当前模型和存储量:
- import UIKit
- let device = UIDevice.current
- device.name // "iPhone 11 Pro"
- let fileManager = FileManager.default
- if let path = fileManager.urls(for: .libraryDirectory, in: .systemDomainMask).last?.path,
- let systemSize = try? fileManager.attributesOfFileSystem(forPath: path)[.systemSize] as? Int
- {
- Measurement<UnitInformationStorage>(value: Double(systemSize), unit: .bytes)
- .converted(to: .gigabytes) // ~256GB
- }
带着14个支持的IOS设备,大多数都有3种配置,假设这贡献了大约32种可能性,或者说是5位。
您可以在MacOS上更进一步,通过处理器计数和RAM数量来进一步区分硬件:
- processInfo.processorCount
- Measurement<UnitInformationStorage>(value: Double(processInfo.physicalMemory),
- unit: .bytes)
- .converted(to: .gigabytes) // 16GB
很难感觉到有多少种不同的mac型号在使用?,但是一个合理的估计大概是2。6或27.
蜂窝网络(~2比特)
知道某人的手机是在威瑞森还是沃达丰,也可以被考虑到指纹。您可以使用CTTelephonyNetworkInfo类的CoreTelephone框架若要查找具有蜂窝服务的设备的提供程序,请执行以下操作:
- import CoreTelephony
- let networkInfo = CTTelephonyNetworkInfo()
- let carriers = networkInfo.serviceSubscriberCellularProviders?.values
- carriers?.map { ($.mobileNetworkCode, $.mobileCountryCode) }
每个国家的供应商数量各不相同,但以美国的4家主要运营商为指导,我们可以说,运营商信息将贡献约2位(如果您安装了多个SIM卡,则贡献更多)。
通信首选项(2位)
更普遍的是,即使知道某人是否可以发送短信或电子邮件,也可以被考虑到指纹中。可以在没有权限的情况下通过MessageUI框架.
- import MessageUI
- MFMailComposeViewController.canSendMail()
- MFMessageComposeViewController.canSendText()
识别信息的其他来源
如果数字指纹的使用看起来很奇怪的话,那只是触及了公司和研究人员如何绕过你的隐私的表面而已。
GeoIP与相关网络速度
虽然通过传统的API访问地理位置需要明确的授权,但是第三方可能能够根据访问Internet的方式对您所处的世界的位置有一个大致的了解。
按源IP地址定位广泛用于区域锁定和本地化。您还可以将此信息与平时测量到已知位置的主机,以便更准确地定位位置。(Weinberg,Cho,Christin,Sekar,&Gill,2018):
- ping -c 99.24.18.13 # San Francisco, USA
- --- 99.24.18.13 ping statistics ---
- packets transmitted, packets received, 0.0% packet loss
- round-trip min/avg/max/stddev = 11.900/12.184/12.895/0.380 ms
- ping -c 203.47.10.37 # Adelaide, Australia
- --- 203.47.10.37 ping statistics ---
- packets transmitted, packets received, 0.0% packet loss
- round-trip min/avg/max/stddev = 202.122/202.433/203.436/0.504 ms
电池健康
目前还不清楚这是否在IOS中引起关注,但取决于UIDevice电池API是,您可以使用它们来识别设备的电池健康。(Olejnik,Acar,Castelluccia,&Diaz,2016年)
- var timestampedBatteryLevels: [(Date, Float)] = []
- if UIDevice.current.isBatteryMonitoringEnabled {
- timestampedBatteryLevels.append((Date(), UIDevice.current.batteryLevel))
- }
因此,电池级API是在Firefox 55中删除.如果这看起来很奇怪,那么考虑一下苹果公司(Apple)最近发布了一项iOS的安全更新,因为研究人员证实,陀螺仪校准设置中的微小差异可以用来唯一地识别设备。(张,贝雷斯福,雪莱,2019年)
另外,如果你想一起进阶,不妨添加一下交流群[1012951431],选择加入一起交流,一起学习。期待你的加入!(进群可领取学习礼包)
参考文献
- de Montjoye,Y.-A.,Hidalgo,C.A.,Verleysen,M.,&Blondel,V.D.(2013年)。在人群中独一无二:人类移动的隐私范围。科学报告, 3、1376号。https://doi.org/10.1038/srep01376
- Sweeney,L.(2000年)。简单的人口统计往往能识别出独特的人。卡内基梅隆大学,数据隐私...工作文件。从http://dataprivacylab.org/projects/identifiability/检索
- Weinberg,Z.,Cho,S.,Christin,N.,Sekar,V.,&Gill,P.(2018)。如何捕捉代理说谎:验证网络代理的物理位置与主动地理定位。在……里面2018年因特网计量会议记录(第203-217页)。纽约,纽约,美国:ACM。https://doi.org/10.1145/3278532.3278551
- Olejnik,L.,Acar,G.,Castelluccia,C.,&Diaz,C.(2016)。漏水的电池。在……里面第十次数据隐私管理和安全保证国际讲习班的订正论文-第9481卷(第254至263页)。纽约,纽约,美国:斯普林格-维拉格纽约公司。https://doi.org/10.1007/978-3-319-29883-2_18
- 张,J.,贝雷斯福德,A.R.,&Sheret,I.(2019)。SensorID:用于智能手机的传感器校准指纹。在……里面第40届IEEE安全与隐私专题讨论会会议纪要...IEEE。
翻译地址:https://nshipster.com/device-identifiers/
iOS开发高级分享 - iOS上的设备标识符和指纹的更多相关文章
- iOS开发高级分享 - iOS的可折叠表视图
导言 我曾经开发过一个iphone应用程序,它显示了大量的输入,这些输入分为不同的类别,在`UITableView`...若要更改其中一个输入的值,用户按下表视图中的对应行,并在出现的单独屏幕中更改该 ...
- iOS开发高级分享 - Unread的下拉式选单
解构革命的演变 背景 2013年中期,RSS世界遭受了沉重打击.谷歌宣布,他们(*的*)RSS订阅服务,[谷歌阅读器],是被关闭了.有了它,数以百万计的声音突然惊恐地大叫,并突然保持沉默. 使用量下降 ...
- iOS开发——高级篇——iOS开发之网络安全密码学
一.非对称加密 - RSA : + 公钥加密,私钥解密: + 私钥加密,公钥解密: + 只能通过因式分解来破解 二.对称加密 - DES - 3DES - AES (高级密码标准,美国国家安全局使用, ...
- iOS开发——高级篇——iOS 项目的目录结构
最近闲来无事去面试一下iOS开发,让我感到吃惊的,面试官竟然问怎么分目录结构,还具体问每个子目录的文件名. 目录结构确实非常重要,面试官这么问,无疑是想窥探开发经验.清晰的目录结构,可让人一眼明白相应 ...
- iOS开发——高级篇——iOS中如何选择delegate、通知、KVO(以及三者的区别)
在开发IOS应用的时候,我们会经常遇到一个常见的问题:在不过分耦合的前提下,controllers[B]怎么进行通信.在IOS应用不断的出现三种模式来实现这种通信:1委托delegation2通知 ...
- iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)
关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...
- iOS开发——高级篇——iOS 强制退出程序APP代码
1.先po代码 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:self.exitapplication message:@" ...
- iOS开发——高级篇——iOS中为什么block用copy属性
1. Block的声明和线程安全Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非ARC ...
- iOS开发——高级篇——iOS 中的 NSTimer
以前的老代码在使用 NSTimer 时出现了内存泄露 NSTimer fire 我们先用 NSTimer 来做个简单的计时器,每隔5秒钟在控制台输出 Fire .比较想当然的做法是这样的: 1 2 3 ...
随机推荐
- 创建一个自己的Vue UI组件库,并将它发布在npm上
本文仅限于入门级,没有成规模制作,希望能对你有所帮助. 因为在开发多个项目中可能会用到同一个组件,那么我们通过复制粘贴的形式更新,无异于是笨拙的,我们可以通过上传到npm后,不断迭代npm包来实现更新 ...
- python pytesseract——3步识别验证码的识别入门
验证码识别是个大工程,但入门开始只要3步.需要用到的库PIL.pytesserac,没有的话pip安装.还有一个是tesseract-ocr 下载地址:https://sourceforge.net/ ...
- FFmpeg(六) 播放视频之GLSurfaceView显示RGB数据
一.播放视频说明 1.两种方式播放视频 ①shader播放YUV,后面再介绍. ②RGB直接显示数据,简单.性能差,用到FFmpeg的格式转换,没有shader效率高.本文介绍这个方式. 2.GLSu ...
- mac下安装rabbitmq
使用homebrew安装rabbitmq,命令如下: brew install rabbitmq 安装的位置如下/usr/local/Cellar/rabbitmq/3.7.18 进入到sbin目录下 ...
- 并发新构件之DelayQueue:延时队列
DelayQueue:延时队列,首先是一个队列,所以可以持有对象,但是仅限于实现了Delayed接口的对象.重写getDelay()和compareTo()(因为要比较)方法: 通俗来讲:延时队列的就 ...
- 算法学习之剑指offer(十一)
一 题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. import java.util.*; ...
- 关于CSS Grid Layout的代码解释
.wrapper { display: grid; /*生成grid类型块级网格*/ grid-template-columns: repeat(3, 1fr); /*设置显示的列网格线,且重复3次1 ...
- Roadmap of FE
未完待补充......
- MySQL从库生成大量小的relay log案例模拟
最近看到"八怪"写的<MySQL:产生大量小relay log的故障一例>,因之前也遇到类似的情况,一直没搞懂原理及复现,看完此文章后,本着实践是检验真理的唯一标准的原 ...
- std::to_string
头文件 #include <string> std::string to_string( int value ); std::string to_string( long value ); ...