Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Importance of Privacy on iOS

The Importance of Privacy on iOS

A lot of time Privacy of my data as a user is not a priority for Developers. Wether it’s my calendar, my contacts, my location, I want as a user to be able to use an app without all of those attacks in my privacy.

I want to summarise everything an iOS developer should do to ensure the most critical user can still use my app in some regards, and not just say “I need all your information” like on other platforms.

This is the beauty of iOS, being able to fine grained (although not enough) so let’s do this all together, as a beautiful community concerned by Privacy.

Transcript

  1. The Importance of Privacy on iOS • Manu @stuffmc Carrasco

    Molina • Apple Technologist @ .com • Founder of Swi"Conf.com [Est. 2012] • Dad of 4, Environment & Refugees Activist Notifications (Can't decide when) @stuffmc • The Importance of Privacy on iOS 1
  2. iS Who's Privacy? @stuffmc • The Importance of Privacy on

    iOS 2
  3. Mine! A look at the Karma-Oriented APIs @stuffmc • The

    Importance of Privacy on iOS 3
  4. What we'll cover • Siri & Search • Photos •

    Contacts • Location • Calendar @stuffmc • The Importance of Privacy on iOS 4
  5. What we won't do • The other parts. Other flavor

    of this talk. • Be exhaustive. We'll scratch o"en. • The whole APIs. Only the privacy parts. • GDPR / DGSVO / RDPG. Good Stuff though. • Maybe I don't have all the new iOS 12 things ;) @stuffmc • The Importance of Privacy on iOS 5
  6. My Privacy.app • Super simple demo app • Link to

    Privacy settings • Contacts, Calendar, Location • ... and... Wait, Siri?! @stuffmc • The Importance of Privacy on iOS 6
  7. ! Siri & Search • By default for every app

    • Settings sometimes for app • Sometimes not. • Always in Siri & Search Based on how you use your app. SAY WHAT?! @stuffmc • The Importance of Privacy on iOS 7
  8. import @stuffmc • The Importance of Privacy on iOS 8

  9. Photos @stuffmc • The Importance of Privacy on iOS 9

  10. Ask Permission PHPhotoLibrary.requestAuthorization { switch $0 { case .authorized: case

    .denied: case .notDetermined: // User has not yet made a choice case .restricted: // Parental controls being in place? } } @stuffmc • The Importance of Privacy on iOS 10
  11. Ask Permission PHPhotoLibrary.requestAuthorization { switch $0 { case .authorized: case

    .denied: case .notDetermined: // User has not yet made a choice case .restricted: // Parental controls being in place? } } App has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an UsageDescription key with a string value explaining to the user how the app uses this data. @stuffmc • The Importance of Privacy on iOS 11
  12. Ask Permission <key>NSPhotoLibraryUsageDescription</key> <string>To visualize your photos on a map</string>

    @stuffmc • The Importance of Privacy on iOS 12
  13. Ask again @IBAction func givePermission() { if let url =

    URL(string:UIApplicationOpenSettingsURLString) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } } @stuffmc • The Importance of Privacy on iOS 13
  14. Ask again @stuffmc • The Importance of Privacy on iOS

    14
  15. A picture worth a 1000 Metadata @stuffmc • The Importance

    of Privacy on iOS 15
  16. A picture worth a 1000 Metadata class Image: NSObject, MKAnnotation

    { var asset: PHAsset var dateFormatter: DateFormatter init(asset: PHAsset, dateFormatter: DateFormatter) { self.asset = asset self.dateFormatter = dateFormatter super.init() } var coordinate: CLLocationCoordinate2D { get { return asset.location!.coordinate } } var title: String? { get { return dateFormatter.string(from: asset.creationDate!)} } } @stuffmc • The Importance of Privacy on iOS 16
  17. UIImagePickerController User decides5 which pictures he gives let picker =

    UIImagePickerController() picker.sourceType = .photoLibrary picker.delegate = self present(picker, animated: true) { } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { print(info) } 5 This is simple UIKit, btw, not in the Photos framework. @stuffmc • The Importance of Privacy on iOS 17
  18. UIImagePickerController: the info Dictionary "UIImagePickerControllerImageURL" file:///path/to/F54AF01F-C12F-4DE9-9266-06D2DD799C05.jpeg "UIImagePickerControllerReferenceURL" assets-library://asset/ asset.JPG?id=106E99A1-4F6A-45A2-B320-B0AD4A8E8473 "UIImagePickerControllerOriginalImage"

    <UIImage: 0x6040002a79e0> size {4288, 2848} orientation 0 scale 1.000000 @stuffmc • The Importance of Privacy on iOS 18
  19. import @stuffmc • The Importance of Privacy on iOS 19

  20. Contacts NSContactsUsageDescription TCC__CRASHING_DUE_TO_PRIVACY_VIOLATION__: App has crashed because it attempted to

    access privacy-sensitive data without a usage description. Info.plist must contain an NSContactsUsageDescription key with a string value explaining to the user how the app uses this data. @stuffmc • The Importance of Privacy on iOS 20
  21. Info.plist @stuffmc • The Importance of Privacy on iOS 21

  22. Out of Process Alert • Start App • Wait Alert

    • Quit app • Allow app @stuffmc • The Importance of Privacy on iOS 22
  23. Contact The good (developer) let predicate = CNContact.predicateForContacts(matchingName: "Appleseed") let

    descriptors = [CNContactGivenNameKey, CNContactFamilyNameKey] CNContactStore().unifiedContacts(matching: predicate, keysToFetch: descriptors) @stuffmc • The Importance of Privacy on iOS 23
  24. Contact — The bad let descriptors = [all the friggin

    properties] <CNContact: givenName=John, familyName=Appleseed, organizationName=(null), phoneNumbers=( "<CNLabeledValue: label=_$!<Mobile>!$_, value=<CNPhoneNumber: stringValue=888-555-5512, initialCountryCode=(null)>>", "<CNLabeledValue: label=_$!<Home>!$_, value=<CNPhoneNumber: stringValue=888-555-1212, initialCountryCode=(null)>>" ), emailAddresses=( "<CNLabeledValue: label=_$!<Work>!$_, value=John-Appleseed@mac.com>" ), postalAddresses=( "<CNLabeledValue: label=_$!<Work>!$_, value=<CNPostalAddress: street=3494 Kuhl Avenue, city=Atlanta, postalCode=30303, country=USA, countryCode=us>>", "<CNLabeledValue: label=_$!<Home>!$_, value=<CNPostalAddress: street=1234 Laurel Street, city=Atlanta postalCode=30303, country=USA, countryCode=us>>" )> @stuffmc • The Importance of Privacy on iOS 24
  25. Contact — The ugly predicate = CNContact.predicateForContactsInContainer( withIdentifier: store.defaultContainerIdentifier() )

    Every Single Contacts of your users! Go ahead, upload to the server!!! @stuffmc • The Importance of Privacy on iOS 25
  26. Write a message to ONE friend? @stuffmc • The Importance

    of Privacy on iOS 26
  27. Use iMessage, Wire4 or else • Doesn't ask acess to

    your address book • Doesn't Geo Locate you • On iOS Signal & Telegram asks as well • Haven't tried Threema myself yet 4 Because not everybody has Apple Hardware :( @stuffmc • The Importance of Privacy on iOS 27
  28. Always check authorisation status [Contacts] Access to Contacts denied with

    error: Error Domain=CNErrorDomain Code=100 "Access Denied" This application has not been granted permission to access Contacts. let status = CNContactStore.authorizationStatus (for: .contacts).rawValue @stuffmc • The Importance of Privacy on iOS 28
  29. Always check authorisation status CNAuthorizationStatus /*! The user has not

    yet made a choice regarding whether the application may access contact data. */ CNAuthorizationStatusNotDetermined = 0, /*! The application is not authorized to access contact data. * The user cannot change this application’s status, possibly due * to active restrictions such as parental controls being in place. */ CNAuthorizationStatusRestricted, /*! The user explicitly denied access to contact data for the application. */ CNAuthorizationStatusDenied, /*! The application is authorized to access contact data. */ CNAuthorizationStatusAuthorized } @stuffmc • The Importance of Privacy on iOS 29
  30. Always check authorisation status if [.authorized, .notDetermined].contains( CNContactStore.authorizationStatus(for: .contacts)) {

    // You can proceed and/or ask for the first time } else { // Won't have access til some user/admin action happens } @stuffmc • The Importance of Privacy on iOS 30
  31. CNContactStore — Me only for macOS? unifiedMeContactWithKeys(toFetch: [CNKeyDescriptor]) macOS 10.11+

    Not available on iOS Why, ?! ! @stuffmc • The Importance of Privacy on iOS 31
  32. Which Properties are accessed? CNContactNamePrefixKey CNContactGivenNameKey CNContactMiddleNameKey CNContactFamilyNameKey CNContactPreviousFamilyNameKey CNContactNameSuffixKey

    CNContactNicknameKey CNContactOrganizationNameKey CNContactDepartmentNameKey CNContactJobTitleKey CNContactPhoneticGivenNameKey CNContactPhoneticMiddleNameKey CNContactPhoneticFamilyNameKey CNContactPhoneticOrganizationNameKey @stuffmc • The Importance of Privacy on iOS 32
  33. Which Properties are accessed? CNContactBirthdayKey CNContactNonGregorianBirthdayKey CNContactNoteKey CNContactImageDataKey CNContactThumbnailImageDataKey CNContactImageDataAvailableKey

    CNContactTypeKey CNContactPhoneNumbersKey CNContactEmailAddressesKey CNContactPostalAddressesKey CNContactDatesKey CNContactUrlAddressesKey CNContactRelationsKey CNContactSocialProfilesKey CNContactInstantMessageAddressesKey @stuffmc • The Importance of Privacy on iOS 33
  34. You don't need to ask permission • Only selecting one

    or more contacts? • Want to see/show which properties you'll give/have? Enter the wonders of... @stuffmc • The Importance of Privacy on iOS 34
  35. import @stuffmc • The Importance of Privacy on iOS 35

  36. ContactsUI let picker = CNContactPickerViewController() picker.delegate = self present(picker, animated:

    true) { // The first time, you might explain // the user he needs to select a contact } func contactPicker(_ picker: CNContactPickerViewController , didSelect contact: CNContact) { } @stuffmc • The Importance of Privacy on iOS 36
  37. Multiple func contactPicker(_ picker: CNCPVC didSelect contacts: [CNContact] ⚠ single

    will be ignored func didSelect contact won't be called @stuffmc • The Importance of Privacy on iOS 37
  38. Contact with Location? // New since iOS 11 CLGeocoder().geocodePostalAddress(CNPostalAddress) {

    ([CLPlacemark]?, Error?) in mapView.addAnnotation (e.g.) }) extension CLPlacemark: MKAnnotation { public var coordinate: CLLocationCoordinate2D { get { return self.location!.coordinate } } } @stuffmc • The Importance of Privacy on iOS 38
  39. Location And MapKit, of course. • No question asked yet

    • Knows I'm in Germany • Not my regional settings • IP Address? @stuffmc • The Importance of Privacy on iOS 39
  40. showsUserLocation • Not doing anything without permission. • No warning

    in Xcode ('s console) either. Bad. • Obviously takes a moment func mapView( _ mapView: MKMapView, didUpdate userLocation: MKUserLocation) { mapView.setCenter(userLocation.coordinate, animated: true) } @stuffmc • The Importance of Privacy on iOS 40
  41. .request*Authorization() WhenInUse / Always let locationManager = CLLocationManager() func viewDidAppear(_

    animated: Bool) { locationManager.requestWhenInUseAuthorization() // or locationManager.requestAlwaysAuthorization() @stuffmc • The Importance of Privacy on iOS 41
  42. The App hasn't crashed App has attempted to access privacy-sensitive

    data w/o a usage description. Info.plist must contain NSLocationWhenInUseUsageDescription with a string explaining to the user how the app uses this data OR ...contain both NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationWhenInUseUsageDescription with string... @stuffmc • The Importance of Privacy on iOS 42
  43. With great power... • Dev: Do you really need access

    to location infos when not using the app? • User: Do you really want this app to know where you are — all time, every time?! • Battery! This would be good for another talk. We as developer are also environmentally responsible of our acts! @stuffmc • The Importance of Privacy on iOS 43
  44. User is asked • String from WhenInUse @stuffmc • The

    Importance of Privacy on iOS 44
  45. User is asked with 3 options • Only using string

    for AlwaysAndWhenInUse @stuffmc • The Importance of Privacy on iOS 45
  46. Explanation in the settings NSLocationWhenInUseUsageDescription @stuffmc • The Importance of

    Privacy on iOS 46
  47. import @stuffmc • The Importance of Privacy on iOS 47

  48. Calendar Using NSPredicate? Can't use true for all events predicate

    was not created with EKCalendarStore methods Before asking for permissions, no real crash. [EventKit] Error getting all calendars: Error Domain=EKCADErrorDomain Code=1019 "(null)" [EventKit] Error (1019) in reply block for CADDatabaseFetchCalendarItemsWithPredicate attempt 1/3 [EventKit] Error (1019) in reply block for CADDatabaseFetchCalendarItemsWithPredicate attempt 2/3 [EventKit] Error (1019) in reply block for CADDatabaseFetchCalendarItemsWithPredicate attempt 3/3 [EventKit] All retries exhausted for CADDatabaseFetchCalendarItemsWithPredicate @stuffmc • The Importance of Privacy on iOS 48
  49. requestAccess(to: .event) or Access(to: .reminder) @stuffmc • The Importance of

    Privacy on iOS 49
  50. requestAccess(to: .event) or Access(to: .reminder) enum EKAuthorizationStatus : Int {

    case notDetermined case restricted case denied case authorized } == PHAuthorizationStatus || CNAuthorizationStatus @stuffmc • The Importance of Privacy on iOS 50
  51. To the next crash ...and beyond Has crashed. Must contain

    an NSCalendarsUsageDescription key with a string. blah blah blah. sh.... @stuffmc • The Importance of Privacy on iOS 51
  52. Access all the calendars? 2 EKCalendar {title = Calendar; type

    = Local; allowsModify = YES; color = #FF1493;} public enum EKCalendarType : Int { case local ... case birthday !!!!!!!!!!!!! } 2 Also case calDAV, case exchange, case subscription @stuffmc • The Importance of Privacy on iOS 52
  53. What have you done? store.predicateForEvents(withStart: Date.distantPast, end: Date.distantFuture, calendars: calendar)

    Like I wanna know everything you did and will do1!, right? Wait, 0 Events? Why? 1 Date.distantPast 0000-12-30 00:00:00 +0000 (Year 0?) Date.distantFuture 4001-01-01 00:00:00 @stuffmc • The Importance of Privacy on iOS 53
  54. What have you done? For performance reasons, this method matches

    only those events within a four year time span. If the date range between startDate and endDate is greater than four years, it is shortened to the first four years. Source: 's Predicate for Events Thanks @michel_fortin on coreint.slack.com @stuffmc • The Importance of Privacy on iOS 54
  55. What have you done? let fourYearsAgo = Date(timeIntervalSinceNow: -60*60*24*365*4) let

    predicate = store.predicateForEvents(withStart: fourYearsAgo, end: Date(), calendars: local) store.events(matching: predicate).forEach { // Now $0 is a single EKEvent print($0.title) } @stuffmc • The Importance of Privacy on iOS 55
  56. Where have you been? ! Need to geocode address string?

    if let l = event.location { CLGeocoder().geocodeAddressString(l) { ! Discover EKStructuredLocation and it's CLLocation property event.structuredLocation?.geoLocation @stuffmc • The Importance of Privacy on iOS 56
  57. Structured Location { title = Lima; address = ; geo

    = <-12.05929000,-77.03006000> +/- 0.00m (speed -1.00 mps / course -1.00) @ 5/27/18, 5:26:17 PM Central European Summer Time; abID = (null); routing = (null); radius = 9178.047384; } @stuffmc • The Importance of Privacy on iOS 57
  58. I'll show you where you were. ... and open the

    URL ... and email all your friends @stuffmc • The Importance of Privacy on iOS 58
  59. You can do so much more EKEvent <0x608000110bc0> { title

    = Hanging Around; location = Lima; calendar = EKCalendar; alarms = (null); URL = ; lastModified = 2018-05-27 14:06:12; startTimeZone = Europe/Berlin; location = Lima; structuredLocation = ...; startDate = 2018-05-23; endDate = 2018-05-23 15:00:00; allDay = 0; floating = 0; recurrence = (null); attendees = (null); travelTime = (null); startLocation = (null); }; @stuffmc • The Importance of Privacy on iOS 59
  60. Know your targets 3 • List of my contacts? attendees

    • (Good or bad) Habits? recurrence 3 I have to play the bad guy... @stuffmc • The Importance of Privacy on iOS 60
  61. import @stuffmc • The Importance of Privacy on iOS 61

  62. EventKitUI • Not like ContactUI • Needs access • No

    link to Settings • Can't see events out of process @stuffmc • The Importance of Privacy on iOS 62
  63. Apps I aim to start • Show developers how to

    use the Privacy APIs • Show users what they should be aware of @stuffmc • The Importance of Privacy on iOS 63
  64. References • https://gitlab.com/stuffmc/privacy • https://krausefx.com/privacy • https://developer.apple.com/videos • https://images.apple.com/business/docs/ iOS_Security_Guide.pdf

    • Better Apps through Better Privacy #WWDC 4PM @stuffmc • The Importance of Privacy on iOS 64
  65. Thanks! Questions? https://twitter.com/stuffmc @stuffmc • The Importance of Privacy on

    iOS 65