top | item 6524221

How we fixed the iOS7 forced logout bug that's been affecting so many apps

85 points| jansen | 12 years ago |blog.loom.com | reply

28 comments

order
[+] pat2man|12 years ago|reply
This is not the proper solution. Instead of making your data accessible when the device is locked you should listen for UIApplicationProtectedDataWillBecomeUnavailable and UIApplicationProtectedDataDidBecomeAvailable. Once your keychain item becomes available again you can log the user back in. The keychain will always be available in the foreground.
[+] lnanek2|12 years ago|reply
Sounds like a much better solution than many of the other proposals here, which would end up with the user having to enter their login credentials more often than they'd like.
[+] mpetrov|12 years ago|reply
At Couple, we found a much simpler solution to debug this exact same bug two days ago, and there was no driving needed:

1. Add lock code to your phone

2. Open the app without a debugger attached and start monitoring for significant location changes

3. Minimize app

4. Turn off iPhone

5. Turn iPhone back on.

Now if you wait 3-5 minutes in the same spot, your app will be woken up and will get a significant location change. Much simpler than driving and easily reproducible in the office.

Now to know when the app actually wakes up while you're in the lock screen, I added a local notification as part of the startup process. Now we just keep the phone locked for a few minutes until it shows the local notification, then you unlock it and see the logout problem.

Hope that helps everyone else!

[+] jansen|12 years ago|reply
Nice one, you guys are just smarter than us :)

If we had known that the bug was caused by reboots though, we probably would have saved some gas as well.

[+] zaroth|12 years ago|reply
The workaround is to allow access to the keychain data while the phone is locked? I assume the Loom keychain data (including the users password) is only accessible to the Loom app, just now it's accessible to the app even if the phone is locked. Doesn't give me a warm and fuzzy feeling.

Why not store username and a random token in the keychain instead of the actual password? You create the token on a valid login and keep it on the server and in the keychain. Basically it's a session cookie.

[+] zaroth|12 years ago|reply
From Apple docs:

  kSecAttrAccessibleAlways
  The data in the keychain item can always be accessed regardless of whether
  the device is locked. This is not recommended for application use. Items
  with this attribute migrate to a new device when using encrypted backups.
If the data is always accessible regardless of if the device has ever been unlocked, then by definition it must not be encrypted, or at least, it must not be encrypted with any key actually derived from the user's password!

Consider, for example, iCloud backups. The "kSecAttrAccessibleAlways" data may be encrypted, but its with a key that Apple knows. So using kSecAttrAccessibleAlways sounds a lot like how Google backups store your WiFi password.

As 'itsboncheck' mentions down-thread, a better choice (still a serious compromise) may be...

  kSecAttrAccessibleAfterFirstUnlock
  The data in the keychain item cannot be accessed after a restart until
  the device has been unlocked once by the user. After the first unlock,
  the data remains accessible until the next restart. This is recommended
  for items that need to be accessed by background applications. Items
  with this attribute migrate to a new device when using encrypted backups.
That sounds like whats happening is the value is stored encrypted in flash in the protected area which is locked with the key derived from the user's pin/password, which is what you want... But they must cache the plaintext value in some temp storage to be able to provide it while the device is locked. That's just my speculation, I don't see Apple divulging the source code anytime soon...

Storing a token in the keychain is preferable, because revoking a token is less onerous than nuking a user's password. Keeping the security set to maximum (kSecAttrAccessibleWhenUnlockedThisDeviceOnly) also seems advisable when we're talking about user password, or even access tokens. Just defer the backup task until the device is unlocked.

If you absolutely must proceed with the background task while locked, consider issuing a less-trusted token which is ONLY used for background tasks, and provide the absolute least privileges possible to accomplish the background task when presented with that token.

Also consider rotating it. For example, whenever a user connects with their full-access token, indicating their device is unlocked, it's a good time to expire the old background-task token and provide a new one. This also lets you do a "mass delete" of existing tokens in case of any funny business, and you'll have automatic recovery ("background processing will start working again next time you unlock").

[+] mpetrov|12 years ago|reply
I agree, the whole point of the logout bug is that the keychain is locked, and that happens for a reason. I came up with a different solution that worked great for us:

Just pause the startup process of the app (in a non-blocking way) if accessing the keychain fails at startup. Then during applicationDidBecomeActive the startup continues with access to the keychain data. That way we don't weaken the security of our customers.

[+] e28eta|12 years ago|reply
> I assume the Loom keychain data (including the users password) is only accessible to the Loom app

I'm pretty sure that's only true for non-Jailbroken devices.

[+] pilif|12 years ago|reply
I faintly remember the WWDC session (I wasn't there. I only watched the videos) about background launching to talk about this exact issue. I also remember thinking that this is going to bite people.

I agree with zaroth here: don't downgrade the keychain security for the password. Either do nothing if the phone is not authorized or store a token in more accessible security levels.

That's what the presenter in the session has recommended too.

[+] itsbonczek|12 years ago|reply
If you need keychain access while the device is locked, using "kSecAttrAccessibleAfterFirstUnlock" is definitely recommended over "kSecAttrAccessibleAlways." I don't remember where I heard this (possibly a WWDC video), but I think most attack vectors require the phone to be restarted to work. Maybe someone with more knowledge on iOS security can chime in with details.
[+] dunham|12 years ago|reply
Or "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly" if you're ok with the secret not transferring to another device. This prevents the secret from being exposed in a password protected backup or an iCloud backup.
[+] brandoncor|12 years ago|reply
Oh man. I seriously love you. I've been trying to find a fix for this for about two years now.

My app sometimes launches from the background after the user enters or leaves a region. It looks for a session token (not a password) in the Keychain and would return nil and log the user out. I'm not sure how I never came across kSecAttrAccessibleAlwaysThisDeviceOnly in all my hours trying to find a solution.

By the way, this isn't specific to iOS 7. I've had the same issue since iOS 5.

[+] e28eta|12 years ago|reply
I have a problem with the downgraded protection on the password, but the abuse of significant location change notifications to start background http requests bothers me a lot more.

I hope a follow up post discusses how they removed this "feature" and took advantage of the new API for background updates.

[+] jansen|12 years ago|reply
It's an opt-in feature, well described in the app and per default turned off. We are however implementing the new iOS7 background uploading processes as well.
[+] dilap|12 years ago|reply
I'm inclined to agree, but w/o using the particular app, it's hard to know if it's justified "abuse" (bending of the rules) or not.
[+] baddox|12 years ago|reply
Is there no way to put iOS devices into a debug mode and send fake location data? Android has supported that for a while, and it's much nicer than actually driving around.
[+] robterrell|12 years ago|reply
You can definitely create any number of locations and switch around between them in the Simulator, triggering the significant location change notification without driving around town. Although in their story it was the chatting-while-driving that actually led to finding the problem.
[+] mahyarm|12 years ago|reply
There are some bugs that need actual device usage unfortunately :(
[+] mikeash|12 years ago|reply
Significant location changes weren't enough to trigger the bug by themselves. If you try it in the simulator and no joy, it's natural to go out and try the real thing to be sure.
[+] andyhmltn|12 years ago|reply
Interesting. I've been having this issue with SnapChat recently. It no longer remembers my login. I assumed it was just an issue with the app and not something bigger.
[+] supercoder|12 years ago|reply
If someone presented this fix on my team they'd be fired.
[+] dangrossman|12 years ago|reply
You'd fire him/her instead of suggesting a better solution? How do you retain employees with that kind of threat looming over their heads?
[+] jc4p|12 years ago|reply
Sadly you don't say where you work on your bio so I can't add your company to my "never ever apply at" list.

New OS updates introduce weird bugs that require hacky code to get around. Early adopters will always update to them and then complain to you that your app is broken, making the hacky code required.