Usually, I use Apple Notes app between all my devices. I write ideas for blog posts and tweets there, draft my conference talks and keep track of things I do during a week (for internal reports at work). I often “lock” sensitive notes.
Time to time I try other applications for note-taking and drafting. I’m very concerned about my privacy (not to mention corporate policy, which adds extra layers of tinfoil), and despite the fact that I don’t store passwords and credit cards in note-taking apps anyway, I don’t want publishers to have access to my notes.
This is a short summary of data security flaws I noticed among 6–7 popular note-taking apps. In most cases, these are not “bugs”, but rather “design caveats”. It’s nothing too complicated — for an experienced mobile developer with a security background, it’s just running the typical checks — which security controls are in place and are implemented well.
I’m not going to publish app names or specific bugs — those apps are great, developers are doing a great job, and security is complicated. I’ve suggested help to the developers, so there’s a small chance that some apps will become more secure soon 🤞
1. No protection at all
If notes are stored as plaintext and are synced to other devices as plaintext — that’s not my kind of application ¯\_(ツ)_/¯
2. Password protection only
Apps that allow users to “lock”/”unlock” note using their custom password, Touch ID or Face ID. Until a password is not entered, users can’t read note content.
This is rather cool because apps can use native Apple LocalAuthentication framework and rely on the authentication mechanism of iOS itself.
How to improve?
— Touch ID / Face ID is the second factor, and if a device doesn’t have these capabilities, or user can’t use them now, users should fallback to enter a password. The application should show password screen, and save the password for later usage (but not infinitely, and store securely), until users attempt to unlock next note. It might be a good idea not to store password exactly, but to use key derivation functions (like PBKDF2, bcrypt/scrypt) to derive hash from a password. On unlock — calculate hash again and compare hashes. The app should store the hash in a Keychain.
— Cache password. If a user has several notes “locked”, once a password is entered (or Touch ID or Face ID), the app can cache it for X minutes in a way, that user won’t need to re-enter password again. However, after X minutes, the app should flush the cache and ask password again (pattern is called “repeated authentication”).
— Wrong password attempts. If a user can’t input correct password for 3–5 times, increase the time before attempts (like iOS itself does). This pattern is called “incremental authentication delay”.
— Reset / change password. There should be a way to change the password (set up a new one after a correct input of an old password or Touch ID / Face ID). Reset should work in a similar way.
— Password syncing. Imagine that a user has two devices with the same application, and decides to update their password on one of them. Of course, the password should be updated on both devices / apps. iCloud Keychain might help in this case (be careful, it can be hacked too), or you can build secure cloud storage where the app can store password hashes.
Why it’s not enough?
Password protection is not an encryption.
The content of the note is still plaintext, even if the access is protected. If the application stores the notes in local file storage, they might appear in backups, can be accessible if device access is compromised, and can be leaked from cloud system that syncs/stores them.
3. Bad network security (rely on TLS only)
Of course, all apps now use TLS to send network requests to the backend server. However, TLS is not enough if someone wants to read your notes. In my talks, I describe in more details why sometimes and in some countries, we can’t rely on TLS itself.
During my testing, I could easily intercept and change network requests — which allows me to not only read notes content, investigate API, send not-allowed network requests, but also to unlock some app features available after subscription only. (I was able to access Pro mode features just by changing the value of “is_subscription_active” to true in the response of account_status request ¯\_(ツ)_/¯).
How to improve?
— Use CloudKit and its API instead of your network layer. A simple and easy way to transfer a problem to Apple’s shoulders.
— Use strong TLS certificate settings and rotate certificates often (90 days, as Let’s Encrypt suggests).
— TLS/SSL pinning: hardcode server’s public certificate inside the app and compare it with certificate received from server connection. So if someone nasty (like me 😅) wants to intercept requests, their certificate differs from hardcoded one, so the app breaks the connection. Keep an eye on updating hardcoded TLS certificates in the right time: hardcode several certificated in the app (current and future ones), and rotate the certificate list on new releases.
— Extra layer of encryption. Unfortunately, certificate pinning can be broken even on non-jailbroken devices. For transferring really sensitive data you might want to add an extra layer of encryption like Themis Secure Session, libsodium, noise protocol, but then you need to manage the keys to additional transport layer really well.
4. Bad storage encryption
As we learnt above, password protection is not encryption. From the user perspective, the application works in a similar way — user inputs password / Touch ID / Face ID to “lock”/”unlock” a note, but this time note’s content is encrypted.
To build proper encryption and key management schemes, developers should answer a question — “what is the worst: data leakage or data loss”?
First means that app should not have a way to decrypt data if the user forgot their password (and there are no other ways to prove their identity), second means that app should have a ‘backup’ way to decrypt the data.
How to improve?
— Define exactly what data to encrypt. One application, that I tried, encrypted my notes, but at the same time it generated preview image with note content, that was stored as file next to the encrypted note. Totally visible, a picture, in plaintext. 🙄
— Do not hardcode encryption key inside your app. Never ever. Don’t store it in user defaults or CoreData/SQLite/Realm. Use Keychain (but Keychain can be broken, so protect encryption keys with user-derived keys).
— Use KDF. As described above, users come up with bad and short passwords. So, use KDF to make passwords stronger (longer, more random), or use libraries for storage encryption that use KDF under the hood.
— Access password != encryption key. Imagine that user decided to update their password: if the app uses exactly this password to encrypt the notes, it should decrypt notes with old password and re-encrypt them with a new one (what will happen if the user forgot password? 😉). It’s better to separate user password from encryption key: app should generate a long random encryption key, and store it in the Keychain (or iCloud Keychain). Before encryption/decryption app asks user password / Touch ID / Face ID to make sure that user is really a note-owner, unlocks Keychain, reads encryption key and decrypts the note.
— Change / reset password — depending on your answer to the “what is the worst” question, techniques differ.
— Syncing access passwords and encryption keys. When the application runs on several devices under the same user profile, it needs to sync keys. Sending encryption key in a plaintext (even above TLS) is a bad practice. Use iCloud Keychain (but it can be broken too), encrypt encryption key with a temporary password before syncing (hehe, this is the point where cryptographic rabbit hole opens 🌀).
— Do not manipulate paddings, IV, and salt during encryption, if you don’t know why they are used. Use “hard-to-misuse” cryptographic libraries that are built by cryptographers for developers. As maintainer of Themis, I can’t recommend it enough.
— Check compatibility. If your app should work on multiple platforms, make sure that encryption cipher and keys format are the same. Ensure that notes encrypted on iOS app can be decrypted on Android app (and vice versa, for each platform. Better write tests for that). Use libraries that are built to support multiple platforms ‘out of the box’.
— Versioning. You might want to change the encryption algorithm later, so it’s better to add some information about the encryption version. Add it as a prefix to the encrypted note content, or save as a separate field in note object. Trust me, you’ll need this later.
5. Lack of end-to-end encryption
The best of the best way to encrypt all my notes and to hide them from prying eyes is to use E2EE. In this case, notes are stored and transferred encrypted, in a way that only the owner (me) can access them.
I’d rather pay a subscription fee for the app that uses E2EE, than use a free app that scans my notes and sells data to ads companies (face-khe-khe-book).
E2EE might be really tricky if users have many devices, or if they want to share their (encrypted) notes with other users. Fortunately, I have some workshop-ready applications for mobile platforms, that use Themis as encryption engine and Firebase as a server. For a large distributed applications with E2EE data collaboration — there’s another open source cryptographic engine Hermes (free for non-commercial use) that was built specifically to handle complex cases.
That’s it for today!
All Rights Reserved for