Setting Up SSL for an iPhone App - Hiding From Firesheep...

Njs5x

Users are the most valuable asset, yet, so many iPhone app's don't take advantage of HTTPS, leaving users totally exposed. I've been analyzing some of my favorite iPhone app's lately, and have walked away stunned at how many send my password in plain text and leave me open to session hijacking.

This is how I fixed that problem, step-by-step...


  1. Grab a free SSL Certificate.
  2. SSH'ed into the server and generate a local certificate.
  3. Send this to the new SSL certificate authority.
  4. Wait for email confirmation (no more than 10 minutes).
  5. Follow their instructions to download a newlly generated cert.
  6. Surf to https://your-domain.com with full SSL encryption.
  7. Use this with any iPhone app!

1. Grab a Free SSL Certificate

First things first, register a new domain at Namecheap.com. Why Namecheap? Well, I've been using them for years and love them, but even better, they are giving away free SSL Cert's with every new domain name purchase. Yep! And guess what? You don't even have to use that free SSL Cert for the domain you just bought. Go buy a domain, select a free cert, and then attach it to any domain on Namecheap.

Know this, I've set up and confirmed this cert works from my iPhone app. This is on iOS 4, but does it work on earler versions? Couldn't tell yea, but I hope someone who reads and tries this will let me know... If this cert does not work on older versions, I believe I have a way to upgrade to a more expensive (and more widly used) certificate authority for free (1 year). Let's see how this works for everyone else first...

2. Generate a Local Certificate

We need to setup the file system and generate a local certificate. I'm assuming an install with Apache2 and OpenSSL on a boxen. If not, stop now and get that setup. Okay... On the command line:

cd /etc/apache2
mkdir ssl && cd ssl

openssl req -new -nodes -out /etc/apache2/ssl/[SITE-NAME].csr -keyout /etc/apache2/ssl/[SITE-NAME].key

Replace [SITE-NAME] with the sites name. If http://example.com is the domain, then I use "example" as a site name. Do as you desire... Okay, so now this asks you a bunch of questions. Fill them out. When you get to the "common name" field, make sure to enter an FQDN, so in this example make sure to enter "example.com" - and leave the "challenge password" blank if desired (it's not needed).

3. Send This to the New SSL Certificate Authority.

Okay, now there are 2 files, a .csr and a .key file. Go back to Namecheap and find a link that will active the free SSL certificate. Click "Activate Now" and find the Digital Certificate Order Form page.

For this example my webserver type is 'Apache + OpenSSL' so that's what get's selected in the drop down box. Then you'll want to copy that .csr file from your server (the one just generated) into the 'Enter a csr' textarea. Now this is important. You need to make sure to include the:

-----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----

portions without any leading or trailering spaces, tabs, carriage returns, etc...  Hit next. If the certificate worked you will know on the next screen. If it fails Namecheap will respond as such, and a fix is needed. It's easy to enter the wrong info when generating the new cert. If so, no problem, go back to the server, delete the .csr and .key files, and try again. Remember, the FQDN is important here.

4. Wait for Email Confirmation

Okay, all the information is fill out and an email will arrive within a few minutes. I've waited as long as 10 minutes, but usually no longer.

5. Follow the Instructions to Download Your Newlly Generated Cert

In the email there should be an attachment that will contain a .zip file. This will have the new certificate in it. Now, head on over to the PostivieSSL site and follow the instructions starting on Step Two.

Here's the relevent bit's of my config file (found in /etc/apache2/sites-available/) for this domain:

NameVirtualHost 127.0.0.1:443
<VirtualHost 127.0.0.1:443>

        [...]

        #SSL
    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/my-domain.csr
    SSLCertificateKeyFile /etc/apache2/ssl/my-domain.key
    SSLCertificateChainFile /etc/apache2/ssl/server.ca-bundle

        [...]

    </VirtualHost>
<VirtualHost *:80>
    [...]
</VirtualHost>

Of course, 127.0.0.1 will need to be replaced with the IP address of the server. Also, 'my-domain' is really the name of the .csr and .key files.

Now, I know it says in the email that a .ca-bundle file in included, but for whatever reason mine never is. So I need to go download it manually. Go here, download that file.

Okay! Still With Me?

I know this may seem like a lot the first time going through it. But I can add one of these certs to my server pretty quick now. I have the process down and eveything I'm posting here is just a longer explaination of my personal notes.

6. Let's Try it!

At this point everything should be wired together. Restart Apache, make sure there were no errors, and surf to https://my-domain.com - If you did all the steps correctly you will be presented with a secure and trusted site.

7. Use This With an iPhone App! 

Reading over my last post, Session Management with Devise, you'll be able to follow along. I'm going to be showing this example using the iPhoneOnRails framework from that post.

[ObjectiveResourceConfig setSite:@"https://your-domain.com"];

And that's it! Hahaha, you thought there would be more? The iPhone libraries (for iOS 4) regonize our new PostiveSSL as a secure and trusted certificate.

Need proof? How about a quick demo?

Wireshark, live it, love it, learn it...

First, I need to setup an ad-hoc network on my MacBook so that I can sniff some packets! Analyzing packets in-route allows us to see if our username/password is hidden, or visible. With https we should not be able to view any of our data. Without it, we can see it all...

To get started, I'm going to plug an ethernet cable into my MacBook and tell the iPhone to connect to my MacBook via it's built-in AirPort. Huh!? Well, just follow along...

  1. Plug ethernet cable into MacBook.
  2. Turn on AirPort.
  3. Go to the System Preferences screen ( Apple menu -> System Preferences ).
  4. Select "Sharing" under Internet & Wireless.
  5. Highlight "Internet Sharing" - without checking the checkbox yet.
  6. Select "Ethernet" in the "Share your connection from" dropdown.
  7. Click the "AirPort Options" button.
  8. Name the network and click "Ok" - I don't add a password, this is just temporary.
  9. Check the checkbox for "Internet Sharing" and confirm you wish to do this.
  10. The AirPort icon in the menu bar should be filled with an upward arrow.
  11. On the iPhone, open up the WiFi settings and select the wirelss network just created.
  12. I usually turn off the "Cellular Data" setting under "Network" as well, this just forces the WiFi usage.

So now I've got a WiFi connection from my iPhone through my MacBook. Time to open up Wireshark and sniff me some packets!

* Yea, I know... The video ain't that great... But I have fun making them and I'm sure I'll get better!

*UPDATE:  Small discussion with some great points on Hacker News