Recently about Mac OS X

The Problem

You downloaded and installed the latest 64-bit DMG from MySQL and now you’re getting “could not load driver” errors in DBI (Ruby or Perl) and Rails.

The Cause

In Ruby, the ‘mysql’ and ‘mysql-2’ gems were compiled against older version of the MySql library. Ditto DBD:Mysql module in Perl.

The Solution

Update 6/6/2011: Google lead me to a better solution:

export DYLD_LIBRARY_PATH=/usr/local/mysql/lib/

That should work for everything! But in case it doesn’t, this will fix Rails:

sudo install_name_tool -change libmysqlclient.16.dylib \ 
/usr/local/mysql/lib/libmysqlclient.16.dylib \
/usr/local/lib/ruby/gems/1.9.1/gems/mysql2-0.2.6/lib/mysql2/mysql2.bundle

And this will fix Ruby’s DBI:

sudo install_name_tool -change libmysqlclient.16.dylib  \ 
/usr/local/mysql/lib/libmysqlclient.16.dylib \
/usr/local/lib/ruby/gems/1.9.1/gems/mysql-2.8.1/lib/mysql_api.bundle

Note: you’ll need to substitute both the appropriate path to the gems, and the appropriate version of the MySQL library.

Fixing Perl’s DBI is a little trickier. You need to download the MySql DBD source and run the install_name_tool on the bundle before you install. Something like:

sudo install_name_tool -change libmysqlclient.16.dylib \ 
/usr/local/mysql/lib/libmysqlclient.16.dylib \
/path-to-my-sql-dbd-source-folder-with-the-bundle-file/mysql.bundle

Ever since hearing about Firesheep I've wanted a Safari extension similar to the HTTPS Everywhere extension for Firefox. Frankly, I was puzzled that one didn't already exist, so I set out to write it. The result is SSL Everywhere. The journey is this blog post.

I started the project as an effort to protect myself and others from Firesheep when using Safari on an open public wireless network, much like those found in coffee shops, hotels, and airports everywhere. Firesheep works by hijacking your session, which is basically a way of stealing your active login without needing your username or password.

My goal with SSL Everywhere was to protect someone from a session hijacking attack by ensuring all requests to the originating website were tunneled through SSL. This seemed trivial until I thought about the various kinds of requests that would need to be secured.

  • the original HTML page
  • images
  • external JavaScript files
  • external CSS files
  • inline frames (iframes)
  • object or embed tags for things like videos or applets
  • Ajax requests
  • requests for the favicon

It wasn't until I started to tackle each of the list items that I realized just how limited Safari's extension API is, and ultimately that one could never build a foolproof extension to protect Safari users from session hijacking attacks.

Lessons Learned

If you've spent any significant time writing Safari extensions, you may already be aware of the many restrictions and challenges I wrestled with for hours. Much of what I learned was trial and error, despite well written documentation from Apple. While the documentation does a fair job of describing many of the things you can do with an extension, it doesn't provide as much detail on what you can't do. That's what you'll find below.

No Access to Raw Cookies

The key to avoiding a session hijacking attempt is making sure the attacker can't access the session cookie, or cookies, your browser sends on each request. This can obviously be done by making sure all requests take place over an SSL connection. Unfortunately, you can't guarantee this won't happen since Safari extensions have no opportunity to intercept webpage requests before they occur. A user could easily type http://twitter.com into their address bar and SSL Everywhere couldn't stop the request.

The other option I pursued was having SSL Everywhere attempt to mark session cookies as secure since the browser will not send cookies marked as secure over a non-SSL connection. However, a Safari extension has no additional ability to manipulate cookies than normal JavaScript running on a page, meaning there is no way to read a cookie's path or expiration date for example. So, there's no way for the SSL Everywhere extension to simply mark a cookie as secure without having to guess at, or omit, other cookie information which may be important to the operation of the website.

No beforeload for favicons, Ajax Calls, or Stylesheet References

Apple was responsible for adding the beforeload event to Webkit. This gives scripts (and extensions) the ability to decide whether an external resource should be loaded or not. As stated in the Safari Extensions Development Guide,

Safari 5.0 and later (and other Webkit-based browsers) generates a "beforeload" event before loading each sub-resource belonging to a webpage. The "beforeload" event is generated before loading every script, iframe, image, or style sheet specified in the webpage, for example.

I was thrilled after reading those two sentences because it was exactly what I needed. That is, until I discovered there's no beforeload event fired when the browser requests a website's favicon, makes an Ajax request, or loads an image reference defined in a stylesheet. This leaves a loophole where I can't stop a non-secure favicon reference, Ajax call, or CSS image reference from exposing the session cookies I can't properly mark as secure.

src Attribute Can Not be Changed in beforeload Event Handlers

I ultimately wanted to have a beforeload event listener that would

  1. inspect the source URL being requested
  2. rewrite the source URL to a secure https: version if necessary
  3. replace the resource's insecure reference with the secure https: URL
  4. allow the loading of the resource to proceed with the new, secure URL

Following the above procedure results in the resource being requested with the SSL-secured URL as desired, but will not stop the original load with the original, insecure, URL. You just end up making two requests for the same resource; one over SSL, the other not. Again, another point of exposure for the cookies.

beforeload != before request

It turns out that all the effort described above to leverage the beforeload event was futile. Preventing a resource from loading, as described in Apple's example of blocking unwanted content, stops it from being inserted into the DOM, but does not prevent it from being requested by the browser anyway.

Apple's example documentation states

If your script responds to a "beforeload" event by calling event.preventDefault(), the pending sub-resource is not loaded. This is a useful technique for blocking ads...

Should I have really expected that "the pending sub-resource is not loaded" doesn't imply that it's not requested? Perhaps I wasn't sharp enough to catch that nuance, but once again the cookies are exposed.

Host Page Prototypes Can Not be Changed

When I discovered the beforeload event doesn't fire on Ajax requests, I decided to try to override the XMLHttpRequest open method and rewrite any insecure URLs to a secure version before yielding to the original open implementation. What I found was that you can't modify the prototypes of the page your start or end scripts are being injected into.

I suspect this has something to do with start and end scripts being secluded in their own separate, and randomly named, namespace. Changing around object prototypes never resulted in any errors, it just didn't change the prototypes of the host page and therefore couldn't change the XMLHttpRequest object. Again, another point of exposure for the precious cookies.

Status of SSL Everywhere

If you've read this far it should be obvious that SSL Everywhere cannot guarantee protection against session hijacking attacks, including those from Firesheep. However, it does enhance security by automatically redirecting you to secure versions of many websites and rewriting insecure links to their SSL-encrypted equivalents. If you must use Safari to access popular websites when connected to an open WiFi network, you're probably better off doing it with SSL Everywhere.

We don't offer a pre-built version of the extension for easy installation into Safari because we don't want people to casually install it and forget that it's not completely secure for all sites. If people find it valuable nonetheless, then we may consider creating the extension bundle in the future.

Try It!

If you'd like to try SSL Everywhere you can find the source code on Github. It's open source software licensed under the GPL version 2 license, primarily because it borrows code from HTTPS Everywhere. If you can come up with solutions to any of the problems I encountered, please let me know!

Recently I got a brand spankin new MacBook Pro (MBP) to replace my three-year-old one. One of the things I did not want to deal with is setting up a new computer from scratch and reconfiguring and reinstalling everything I already had on my old MBP. I have things pretty-well organized, I know where things are, and I remember when I rebuilt from scratch from Tiger to Leopard I lost a bunch of settings and such because I hadn't used any kind of migration software. Not this time. This time I wanted my new computer to essentially be my old computer, but with more memory and faster with no hassles.

There are a few options I considered. First, simply take a SuperDuper backup and restore directly to the new MBP. I researched this a lot, talked to people who've done this both successfully and unsuccessfully, and talked to a Genius at the Apple store. The second option was to use the Migration Assistant to transfer from old to new. After all the research, I decided against restoring from SuperDuper for several reasons. First, it seemed to be hit or miss: some people reported success and some did not. Second, and more importantly, I was transferring from a circa August 2006 MBP, in fact one of the first revs that had the Intel chips inside, to a circa June 2009 MBP with the new trackpad and all the other updated jazz. I was mostly concerned that there could have been enough difference between the old and new computers' hardware and software drivers and that a direct restore would not contain up-to-date drivers and whatever else that could screw things up. So I chose to explore using Migration Assistant, which promised a very easy transfer of all files and settings.

So then I ran into the first snag, which is that Migration Assistant does not transfer File Vault-ed user accounts, and I happen to use FileVault. Doh. So I thought, "OK no problem I'll simply turn off FileVault on the old machine first." Except that I only had about 7GB of space left on my hard drive, and turning FileVault off needs about as much free space as your home directory currently takes up. So if my home directory is currently 50GB, then I need about 50GB free. Double Doh, because I didn't have that kind of space! To solve all these problems, here is what I did, for anyone else who might be trying to do the same thing:

Step 1 - Backup Original Mac

Make a SuperDuper backup of the old MBP onto a portable external hard drive. (I actually made two copies on two different external hard drives, just in case something got screwed up later.) The external drive should contain plenty of space, enough so you can turn off FileVault on your home directory.

Step 2 - Turn off FileVault on External Drive

Restart the old Mac and boot from the SuperDuper backup. (You hold down the option key during startup to get the screen where you can choose to boot from the Mac hard drive or the SuperDuper backup on the external drive.) Note at this point you are now running Mac OS X on the external hard drive. Log into the FileVault-ed account, go to System Preferences, and turn FileVault off. (This is why you needed to make sure the external drive has enough space to turn off FileVault, since you are turing it off there, not on your Mac's hard drive!) Now go grab something to eat and/or watch a movie as this step can take a few hours depending on how much data you have.

Once complete, log out and shut down the external drive. You are now ready to transfer.

Step 3 - Prepare for Migration Assistant on New Mac

Log into your new Mac, and connect the external drive that contains the freshly un-FileVault-ed SuperDuper bootable backup of the original Mac. If you or someone else already setup a new user account on the new Mac that has the same username as your old account does, then create a new account with Administrator privileges (e.g. "MigrationAccount") and then delete the account that you will be transferring to. For example, if your old Mac account username was "bsmith" and the new Mac has an account with the same username, remove the "bsmith" account on the new Mac. Otherwise when you attempt the migration you might receive the following message like I did the first time I tried: "There is an existing user account with the same name as an account you are transferring." This wouldn't have been an issue, except that the option to replace the account was disabled and so Migration Assistant was refusing to overwrite it. Thus you should delete it first.

Step 4 - Run Migration Assistant

On the new Mac, run Migration Assistant and answer the questions. You'll be transferring from the external SuperDuper backup to the new Mac. The questions are easy and straightforward. Go grab something to drink or watch some TV, as it'll take a while to transfer all your old files and settings from the external drive to the new Mac. I'll just assume everything went well, because it did for me. If something went wrong, well, I don't have answers other than maybe to try, try, try again from scratch.

Step 5 - Turn FileVault Back On

On the new Mac, turn FileVault on for the newly migrated account, e.g. if the "bsmith" account previously had FileVault on, then login as "bsmith" and turn on FileVault in System Preferences. Tick tock. More waiting as Mac OS X encrypts all the data in your home directory. Once this process completes, your new Mac should be pretty much the same as your old Mac, with all the same files and settings like Desktop, Screen Saver, etc. and with all your applications transferred successfully. And you are back up running with FileVault enabled.

Step 6 - Secure Erase External Hard Drive

At this point you have the new Mac setup with FileVault, and the old Mac still has FileVault on as well since you migrated from the external drive. But, the external drive now has unencrypted data sitting around since you turned FileVault off on it. Open up Disk Utility and do a secure erase of the un-FieVaulted external drive. Depending on which option you choose, e.g. "Zero Out Data", "7-Pass Erase", "35-Pass Erase", etc., the erase process can take a long time, as in days. In other words, a 7- pass write overwrites every part of the disk 7 times to sanitize it and make recovery of the unencrypted information much harder, and takes 7 times longer than just zeroing out the data, which writes zeroes all over data on the disk.

I only did a zero out of the data, because I knew I was going to immediately overwrite that external drive with a new SuperDuper backup once I was done. If you need more insurance than that, a 7-pass erase confirms to the DoD 5220.22-M specification which is probably good enough. (Actually I started out using 7-pass erase until I saw it was going to take a day or two, and then I got a tad lazy and just did the zero out. Perhaps that is bad, but I didn't feel like waiting that long, and it's not like I have data for 100,000 employees on my hard drive in an Excel spreadsheet anyway. Just a lot of code and presentations and such, really.)

Step 7 - Backup New Mac

Make a fresh SuperDuper backup of the new Mac.

Coda

Although all the above sounds like it took a long time, the waiting and time was mostly due to having to turn FileVault off and then on and doing the secure erase. Migration Assistant itself takes a fair amount of time but is totally worth it. Overall the entire process from start to finish on my old MBP with a 100GB hard drive containing only 7GB free space took between five and six hours, which is way less time than if I had tried to start over from scratch with the new Mac. I do wonder why Apple cannot just allow Migration Assistant to transfer accounts with FileVault enabled, because then pretty much all you'd need to do is run Migration Assistant directly, and you wouldn't need to go through all the drama.

If you want/need to run VisualVM on a 32-bit Macbook Pro you'll need to do a couple of things. First, download and install Soy Latte, using these instructions - this gets you a Java 6 JDK/JRE on your 32-bit Macbook Pro. Second, download VisualVM and extract it wherever, e.g. /usr/local/visualvm. If you now try to run VisualVM you'll get the following error message:

$ ./visualvm
./..//platform9/lib/nbexec: line 489: /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/bin/java: Bad CPU type in executable

Oops. After looking at the bin/visualvm script I noticed it is looking for an environment variable named "jdkhome." So the third step is to export an environment variable named 'jdkhome' that points to wherever you installed Soy Latte:

export jdkhome=/usr/local/soylatte16-i386-1.0.3

Now run the bin/visualvm script from the command line. Oh, almost forgot to mention that you should also have X11 installed, which it will be by default on Mac OS X Leopard. Now if all went well, you should have VisualVM up and running!

While I was reading through some Apple documentation on Bonjour I stumbled across a discussion on link-local addressing and DNS search domains. While the details of link-local addressing aren't that important here, the discussion on DNS search domains triggered a little light bulb in my brain.

You see, DNS search domains are used as a guide to help your computer lookup an IP address when something simple like "blogs" is typed into your browser's URL. If you setup a DNS search domain of "nearinfinity.com", typing "blogs" will force your computer to first check if there's an address for "blogs.nearinfinity.com". If not it falls back to its default behavior.

If you're a person that spends a lot of time on a small number of websites, you could use DNS search domains to your advantage to make navigating to those sites a snap. For instance, I just setup "nearinfinity.com" as an entry in my DNS search domains on my Mac. Simply go to the network preferences pane, click the advanced button at the bottom left, and then the DNS tab on the resulting popup.

dns_search_domains_osx.jpg

So now, whenever I type "blogs" in my URL I get "blogs.nearinfinity.com". Whenever I type "support" I get "support.nearinfinity.com". I think you probably get the idea. I know I'm no genius for discovering this since it's precisely the reason for having search domains. I just never thought to use them before.