TL;DR: Navigate to Settings > General > About > Certificate Trust Settings and turn the switch on for your custom certificate.
Like many, Charles Proxy has become an indispensable part of my daily toolkit. Every person on my QA team uses it daily for their projects. Recently while testing on iOS 10.3, one of my team members couldn’t get his SSL traffic to proxy. Usually when somebody runs into this, it’s because the person hasn’t installed the Charles Proxy root certificate on the device they’re trying to proxy. Then why you try to proxy SSL traffic in Charles you’ll the following error: SSLHandshake: Received fatal alert: unknown_ca
Charles Proxy will even offer a helpful suggestion:
You may need to configure your browser or application to trust the Charles Root Certificate. See SSL Proxying in the Help menu.
iOS is refusing the SSL handshake because the certificate authority that has issued the SSL certificate being used is not in its Trust Store. Previously to resolve this, we would just need to go to http://ssl.charles in Safari on the device, and we could then install the root CA from Charles and tell the device we want to trust it. In this case, the QA person had already taken these steps. After some digging around, he found the problem.
Settings > General > About > Certificate Trust Testings
The Charles Proxy Custom Root Certificate that he had installed showed up in the list, but its toggle was turned off. While this section existed prior to iOS 10.3, by default when you would install a custom certificate, iOS would implicitly trust it. No further action required. As of iOS 10.3, the default for new custom certificates is to not trust them. If you want to trust the custom certificate you’ve installed (why else would you have installed it?), you’ll need to navigate to the section mentioned above and manually turn the switch on to trust the certificate. Any certificates installed and trusted prior to iOS 10.3 seem to be grandfathered in, so you won’t run into this until you’re trying to use a new root certificate.
After looking at the app bundle with PhoneView and failing to find anything interesting there, I fired up Charles Proxy to have a look at the app’s traffic. The good news is Simple appears to be sending everything over SSL. This means that if, for instance, you’re at the airport and your iPhone is on an open wi-fi network, an attacker will just see encrypted garbage if they look at the traffic going between your iPhone and Simple’s servers. Now the bad news.
Charles Proxy has a wonderful option called SSL proxying. SSL proxying is handy for debugging when your app’s traffic is encrypted, but you want to see the contents. The first issue I noticed with Simple is it doesn’t take any steps to make sure it’s talking to its own servers. SSL guarantees that your connection is encrypted, but it doesn’t necessarily guarantee who is on the other end of that encrypted tunnel. Without the app validating that it’s talking to the server it should be talking to, it’s possible for an attacker to perform a man-in-the-middle attack.
Editor’s Note:In iOS (and any modern web browser), there is a list of trusted CAs that is bundled with the OS. These CAs are who issue SSL certificates. When an SSL connection is established, if the SSL certificate’s URL does not match the URL that a connection is being made to, a warning will be raised and the connection will fail. This means that a malicious attacker can’t use his SSL certificate that he may have acquired for fakebank.com to perform a MITM attack with requests that are going to https://simple.com. Some sort of compromise of the chain of trust in SSL would have to take place, like a CA being hacked and generating a phony certificate for Simple’s servers. When I originally said that Simple doesn’t take any steps to make sure it’s talking to its own servers, what I meant was it’s not performing any validation outside of what SSL inherently gives on iOS. There is an additional step that can be performed that is called SSL pinning. With SSL pinning, the app can take matters into its own hands to perform additional validation on who it’s talking to, rather than relying on the more general list of trusted CAs. This would ensure that in cases like a CA being hacked, there would be an additional layer of security by the app to validate it’s still actually talking to Simple’s servers. However, it’s worth emphasizing that without such a compromise taking place, user data is encrypted and secure with Simple’s app. All data is going over an SSL connection, and some compromise of SSL would need to occur for this data to be at risk in this scenario.
Normally the way SSL works is the client will setup an encrypted connection with the server before sending data to it. The way a man-in-the-middle attack works is the attacker intercepts your communications to the server and the server’s communication back to you. The client has an encrypted tunnel set up with what it believes to be the server. The server has an encrypted tunnel set up with what it believes to be the client. In reality both are just talking to the attacker and the attacker relays the traffic on after it’s able to take a look at it.
A MITM attack isn’t extremely likely on iOS because iOS ships with a list of trusted SSL certificate authorities. Using an app like Charles Proxy, you use a self-signed SSL certificate which iOS won’t trust unless you explicitly tell it to. That said, SSL is not foolproof and there have been instances in the past of it being exploited, and even of attackers creating phony SSL certificates signed by a legitimate and trusted CA.
Ultimately this isn’t something users have to worry about too much, but it is something Simple should fix. The app should be making sure it’s talking to Simple’s servers and Simple’s servers should make sure that it’s really the app that’s talking to them.
What’s more interesting is what you find once you start looking at Simple’s traffic. Since Simple isn’t doing any certificate pinning, we can enable SSL proxying in Charles and watch the traffic that Simple is sending and receiving. The first thing that jumps out is the request to https://api.simple.com/user-api/mobile-auth-tokens when you sign in to your account. Included in the request are your plaintext username and plaintext passphrase. The request is sent over SSL, but this doesn’t guarantee security and when dealing with such sensitive data, more security measures should be taken.
To be fair, up until this point, I haven’t seen anything that Simple is doing wrong that other banks are doing right. Of the two other banks I have accounts with, neither do pinning of SSL certificates or have any additional security to protect your username and password when signing in. So far Simple’s behavior seems par for the course. So far their security is just as disappointing as my other banks.
But wait, there’s more… There’s another request sent when you sign in: https://api.simple.com/user-api/users/UUID. The body of the request isn’t all that exciting, but the contents of the response are. It seems to include all of our personal info including full name, email, street address, date of birth, and social security number. Yes, your social security number. Simple’s server is sending all of this data back to your app when you log in, and as most of this info doesn’t seem to be used by the app anywhere, it’s unclear why they feel the need to send it.
After reading their security policy I felt hopeful that they’d be receptive to my concerns, so I sent an email to their security team. After eight days, I sent a followup to make sure my original email hadn’t been lost. Finally, a reply:
My apologies for not responding sooner; we did receive your report and I’ve discussed the issues you’ve raised with the team.
We are continuously working to improve the security of our solutions, and you can expect to see steady improvements as we continue to build out our platform. The challenges with ensuring the effectiveness of SSL are well-understood and under constant review inside the organization. In addition, it does look like we are transmitting more data than we absolutely need to and that is something that we are actively working to improve.
Thank you again for your message, and please do not hesitate to contact us again. We also provide a GPG key for communicating security issues with Simple on the Security page at www.simple.com; please feel free to use that in the future if you are able.
Director of Information Security
So it sounds like maybe they’ll fix this at some point… or maybe not, I’m not sure. I’ve seen restaurants respond with more urgency when they screw up my hamburger. For a company that I’ve entrusted with my personal and financial data I expect them to treat security with the utmost importance. I expect them to fix security oversights as quickly and apologetically as possible. Since the company does not seem to share my enthusiasm there, I felt that the responsible thing to do was inform other users of these shortcomings so that they can make an educated decision on what to do with their own accounts. I’m still hopeful that eventually Simple will fix these issues, but in the meantime their users deserve to know how the company is handling their information.
Update #1 12/20/12 3:00PM – Simple has responded to several users on Twitter in order to try and address their concerns. Happy to see them actively responding to users and looking forward to seeing the issues actually fixed.
Update #2 12/21/12 9:00AM – I received a tweet from Brian Merritt, the Director of Engineering at Simple, asking if I’d be willing to give him a call and talk.
Good news. The SSN issue has been fixed as of last night. If you go look at your traffic now, your SSN is no longer being sent back by the server. Brian also reassured me that the SSL certificate pinning is an issue that they were aware of and have been working on. Unfortunately that sort of fix will require an app update, so it’s something we’ll have to wait on, but it does indeed sound like the fix is coming.
When it comes to testing slow network conditions, we already covered Network Link Conditioner. But what’s that you say? You’re wondering if there’s a more robust and extensive tool for network testing and debugging? Well I’m glad you finally asked, because as it turns out, there is, and his name is Charles. Charles Proxy is a cross-platform proxy application that can be used to monitor and manipulate traffic. Go download and install the trial so we can get started.
After starting up Charles you’ll need to configure your device to route its traffic through your computer (unless you’re using the sim, in which case you can skip this part). With your computer and iOS device on the same network, go to your iOS device Settings, then go to Wi-Fi and tap on the blue circle with a white > in it to the right of your network. Scroll to the bottom and under HTTP Proxy, tap Manual. For the Server, enter your computer’s IP address and for the port enter 8888. Close Settings and now your device’s traffic should be going through Charles.
As previously discussed, Network Link Conditioner lacks the ability to specify which traffic you want to throttle; it’s an all or nothing deal. So first, let’s look at Charles’ throttling feature. Go up to the Proxy menu and select Throttle Settings. Check “Enable Throttling” and “Only for selected hosts”. The throttle settings aren’t much different than NLC, but the “Only for selected hosts” option is something new to us. Any hosts added to the list at the bottom will be throttled according to your settings and all other traffic will go through the proxy unthrottled. This makes testing poor network conditions much more tolerable as you can now slow down your app’s traffic while still listening to your Dubstep Nickelback playlist on Pandora uninterrupted. So add whatever hosts you want to throttle to that list. You can easily toggle throttling on and off by pressing ⌘-T at any time. So now that you’re set to test your app on a slow network, let’s have a look at what else we can do with Charles.
By now you might be seeing some URLs appear in the Structure (left) pane of Charles’ main window. These are all the URLs of requests that have gone through Charles so far this session. If your window is still blank, then you must not have much background traffic going on (or you’re not recording in which case, click that record button up top that looks like… well, a record button). Expanding any one of the URLs will show which files on that site are being hit. As you select them, in the right pane you can see more information like the request to the server and the response that came back. If your application is using SSL for its connections, Charles has you covered there too. You’ll just need to go install Charles’ SSL certificates for your computer and for your iPhone (iOS 4 instructions also work on iOS 5 & 6).
Once you have the correct certificates installed, you’ll need to explicitly add all hosts that you want to enable SSL proxying for. While you can just add a wildcard to enable SSL proxying for all hosts, there are a number of websites that won’t play nicely with the type of man-in-the-middle attack Charles uses to make SSL proxying possible. Instead it’s recommended that you explicitly add hosts that you’re actually interested in looking at. You can manually add these hosts under Proxy > Proxy Settings > SSL, or if the host you want to proxy already appears in your list of traffic for this session, you can simply right-click on the host and click SSL Proxying. Now any SSL requests made to that host should show up, and the contents of the request and the response should be visible.
The last feature of Charles that I want to touch on right now is the ability to map to local files. Normally your application will make a request and the server will send it a response. Often times for testing, it’s extremely useful to be able to manipulate the server’s response, especially in apps that rely heavily on data from a server. For example, you might want to verify that your application can handle invalid JSON (I’ve previously run into a 3rd-party JSON parser that crashed when it got invalid JSON), but in testing the server might always give you a valid response. Usually to test this I’ll start by having my application make a normal request and receive a normal response. Then in the Structure pane of Charles, find that request, right-click on it and select Save Response. After saving the server’s response locally, you can edit it to your heart’s content. Once you’ve made whatever edits you want, back in Charles right-click on the request again and now select “Map Local…”. In this dialog you can set the local path for the file that you would like Charles to use (the one you just saved and edited) in place of the server’s response. Now the next time your application makes this same request, Charles will hand it your local file instead. You can use this feature to test for things like making sure your app handles long strings of text, large numbers, or blank values. You know, all those scenarios developers say won’t happen, but they always do. You can manage all the requests you have mapped locally under Tools > Map Local…
So there you have it kids. Charles Proxy is a powerful tool for testing and debugging your applications and their traffic. Hopefully this has helped you get started. The Charles Proxy website also has excellent documentation if you find yourself stuck on something or want to learn more about its other features.