Raam Dev’s Weblog

Avatar

Life is an aftertaste. Drink up and wait for it...

Browser Resolutions of the Interweb

I have often advocated designing websites to support as many screen resolutions and browsers as possible, including tiny mobile devices and text-based web browsers like Lynx (though I prefer Elinks myself). Whether I’m under-the-gun at work, or just designing a new WordPress theme for my blog, when time and resource constraints force me to decide on a minimum resolution I look for statistics to back up my choices. In a perfect world, all sites would be usable with all browser resolutions (and CSS would play nice with all browsers and 1px would be 1px… don’t get me started).

It wasn’t too long ago that a lot of people were still browsing the web with an 800×600 screen resolution. For most of us now though, the only time we see that screen resolution is when we don’t have the correct video drivers installed. W3CSchools keeps lots of interesting web stats based upon visitors to their site, including Browser Display Statistics. Here you can follow a clear trend to higher browser resolutions through the years:

Browser Display Statistics

This lead me to check my the visitor browser resolutions for this blog through Google Analytics. I’ve been keeping stats on this blog since September 2007 and with over 40,000 visits I figured I could get some good metrics:

raamdev.com Visitor Screen Resolutions

These stats seem to indicate the same thing as W3CSchool’s stats: 1024×768 is a clear winner. This got me thinking though. How many of the popular sites out there are viewable in 1024×768? What about 800×600, or even 640×480?

Yet Another Window Resizer is an excellent Firefox add-on that allows you to easily resize your browser to various resolutions. I visited various popular sites and tested their minimum browser resolutions:

[1024x768] - Amazon.com
[1024x768] - eBay
[1024x768] - Yahoo!
[1024x768] - Wikipedia
[1024x768] - CNN
[1024x768] - YouTube
[1024x768] - Apple
[1024x768] - Microsoft
[1024x768] - Digg
[1024x768] - Delicious
[1024x768] - Facebook
[800x600] - Twitter
[800x600] - WordPress 2.7 Admin Dashboard (screenshot)
[640x480] - Google Search (screenshot)
[640x480] - Google News
[640x480] - Google Maps

Clearly most sites have chosen to ignore smaller browser resolutions in favor of supporting only the most popular as a minimum. (Although this blog has a 1024×768 minimum requirement, the main content area is fully visible in 800×600.) The nature of the content presented by the site dictates a lot of the size requirements. For example, Google search presents textual content that can easily be (and most certainly should be) confined to a small area. In fact, the Google search results maintain a 640px width even when you’re using a much higher resolution (leaving a lot of white space to the right, but maintaining readability).

There is much to be said about textual readability on the web, but I’ll leave that for another post.

Not Outsourcing my Comments to IntenseDebate

I’ve been hearing a lot about IntenseDebate recently, in various blog posts and news sites (they were acquired by Automattic, the company behind WordPress, back in September). IntenseDebate is basically a set of tools that allows for enhanced commenting on your blog or website. Two features that caught my attention were Comment Threading and Reply-by-email.

Comment Threading was of particular interest to me because I find that being able to respond directly to a specific comment keeps the comments organized and relevant. Normally the way you respond directly to a comment without threading support is to prefix your reply with the persons name (e.g., “@raamdev That’s a great idea!”), but constantly searching the list of comments for the comment being replied to gets tiresome.

I don’t really have enough comment traffic on this blog to deal with the aforementioned problem on a regular basis, but I decided to install the IntenseDebate WordPress plugin to see how easily I could integrate it. I was impressed with how smoothly the process went. All my old comments (1,300+) were synced to IntenseDebate and there was nothing I needed to change on my theme templates — the entire commenting system was replaced with IntenseDebate’s commenting system, with threading support, a comment reputation point system, and all those other fancy features.

In the end, however, I decided to deactivate the plugin. I didn’t like that my comments were being loaded from an outside source, which both increased the average load time for each page and added yet another dependency on an external service. (In contrast, my Twitter sidebar uses Twitter Tools, which actually syncs tweets to the same database as WordPress and loads them from there. Dependency problems solved! To be fair though, the IntenseDebate plugin maintains a copy of all the comments in the WordPress database, just in case you decide to stop using it.) Customizing the look and feel of the comments also meant modifying CSS through my IntenseDebate account and right from the start I felt the need to customize and make the comment system less “busy” and self-advertising. There were no themes to choose from either. Ugh.

While doing all this thinking about the disadvantages of outsourcing my comments, I came across a post on Robert Nystorm’s blog where he decides to literally outsource all of his comments. Instead of having any form of commenting system, he simply provides a link to reddit, Digg, and StumbleUpon where he encourages people post their comments on his post. His rationale behind this is that people already use these other sites for commenting and those commenting systems are specifically tuned to handle comments. If you can’t beat’em, join’em.

But that’s extreme. Although I can sympathize with some of Robert’s frustration, I think a commenting system, even if only a simple one, is important. While some people may be familiar with reddit, Digg, and StumbleUpon, not everyone will use those sites regularly or, for that matter, want to go through the trouble of creating an account just to post a comment.

Back in September, I wrote about how excited I was to hear that Comment Threading was coming in WordPress 2.7. I hope the features and functionality of IntenseDebate are somehow integrated into WordPress down the road, instead of indefinitely relying on an external service to provide the same functionality.

Stop all the Questions and Definitions!

Sites and services like Facebook and Twitter ask you questions. In fact they can even be configured to pester (i.e., “nudge”) you if for some reason you feel a moral, religious, or social obligation to keep the vast world of unknown people updated with your every mood, feeling, thought, current activity, or location.

I sat down in front of my computer with a splitting migraine, a migraine that had been piercing through my head the entire day, like an alien parasite whose only job was to disrupt, distract, and otherwise make my day as mentally challenging as possible. As I turned on the monitor, I saw that I had left the Twitter website open. “What are you doing?” the screen pestered, as if instantly joining forces with the alien parasite to make my brain work harder. But it had been 22 hours since I last wrote something on Twitter! Oh no! The world is going to end! I must update everyone immediately!

I suddenly realized that as I begin to use more social-networking sites and write more things on my blog, I am increasingly being pestered with questions and buttons that contain definitions of what I should be writing:

Write a New Page
Write a New Post
Write something…
Write another comment…
What are you doing right now?
Write something about yourself.
What are you doing?

How annoying! I mean really, it’s annoying. No, that’s not the alien parasite talking. This stuff is right in line with Google’s growing visual clutter, only worse. It’s bad enough that I come up with an interesting thing to search the Internet for only to have Google’s suggestions magically chase the original query away, but when everywhere I look for an outlet to express myself I find a question or a definition of what I should be writing, we’re bordering on mental invasion and theft!

These subtle things are killing the creative thought process and subtly removing truly free expression. I feel as though I’m fighting to keep my thoughts to myself just long enough to express them genuinely to whomever might be listening (even if that person is only a future version of myself).

Google’s Growing Visual Clutter

Google’s latest “feature” is nothing short of annoying. I fell in love with Google Search for the clean, textual layout of the search results. The colored text I can deal with, but not visual buttons next to every single result! To make matters worse, Google doesn’t provide a way to disable this feature either, so your only two options are logging out of your Google account or installing a Greasemonkey extension.

Oh, and my rant doesn’t end there. Another feature that was recently added, Google Suggest, has been more trouble than it has help. I can’t even count how many times I’ve went to Google something only to have a big list of suggestions instantly erase the original search query from my head. There are hacky ways to disable that too, but come on Google! There should be options to disable this stuff!

HTML Radio Buttons: A blast from the past!

So there I was sitting in my C/Unix class at Harvard barely paying attention to the professor as he talked about HTML forms (!) when I heard him start talking about the history of the HTML radio button. I often wondered why they were called “radio” buttons so I shifted my attention and listened.

He started by trying to explain to a room full of people a third his age how car radios did not always have tiny touch-sensitive buttons and that they used to be single mechanical buttons that when one was pressed, the other would come out (much like the old cassette-based walkman’s).

This little fact fascinated me because I have been using HTML radio buttons for so long and until now, I have been so oblivious to the history behind their name. A quick search on Wikipedia confirmed my professor’s story:

A radio button or option button is a type of graphical user interface widget that allows the user to choose one of a predefined set of options. They were named after the physical buttons used on car radios to select preset stations - when one of the buttons was pressed, other buttons would pop out, leaving the pressed button the only button in the “pushed in” position.

Googlebot Relentlessly Using Bandwidth

When one of my hosting clients complained about continuously running out of bandwidth on his low-traffic site, I took a peek at the access logs and discovered that Googlebot was indexing every single possible day on a simple calendar addon for the phpBB2 forum software installed on the site. (Googlebot is the program that crawls the web indexing everything so you can search for it using Google.)

A quick peek at the access logs showed thousands of Googlebot requests for a forum calendar:

66.249.71.39 - - [01/Sep/2008:17:09:12 -0400] "GET /forums/calendar.php?m=7&d=21&y=1621&sid=79b643b30eer7140adcd2ba76732688a HTTP/1.1" 200 44000 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
66.249.71.40 - - [01/Sep/2008:17:09:33 -0400] "GET /forums/calendar.php?m=4&d=2&y=2188&sid=e4da1ee0a488096e3897a8f15c31cea2 HTTP/1.1" 200 43997 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
66.249.71.40 - - [01/Sep/2008:17:09:44 -0400] "GET /forums/calendar.php?m=12&d=4&y=1624&sid=cc5d5084d158457ce3c7a9d38263f553 HTTP/1.1" 200 44076 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
66.249.71.41 - - [01/Sep/2008:17:10:05 -0400] "GET /forums/calendar.php?m=10&d=15&y=1621&sid=a4e8af0d20715g965b3e616ae6f95004 HTTP/1.1" 200 43751 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
66.249.71.41 - - [01/Sep/2008:17:10:15 -0400] "GET /forums/calendar.php?m=9&d=13&y=2187&sid=80c79b2491ddf3d8d46076d48a6282d1 HTTP/1.1" 200 43896 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
66.249.71.40 - - [01/Sep/2008:17:10:26 -0400] "GET /forums/calendar.php?m=5&d=30&y=1618&sid=f0619ba6517an57bcd6a7e9ca6289a32 HTTP/1.1" 200 43820 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
66.249.71.39 - - [01/Sep/2008:17:10:38 -0400] "GET /forums/calendar.php?m=11&y=2189&d=30&sid=97c0a58bbd2b3914dbf255ea0a2b1a4c HTTP/1.1" 200 44107 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

A quick Google search turned up many others who’ve had the same problem:

Just found exactly the same on one of my client’s sites. They were complaining that despite being a small site, they’d apparently used all of their bandwidth within 4 days.

They had one of these PHP calendars on their site, where you click the day and it tells you what’s on. Googlebot had tried to index EVERY SINGLE POSSIBLE DAY. And, in the first four days of September, had used up all this site’s bandwidth, clocking up an impressive 19,000 hits and 800MB of bandwidth.

You can use robots.txt to tell all decent robots to push off. I’ve just done that. Let’s see if it works!

So I added a file to the root web directory for the site and named it robots.txt. Inside, I put the following:

User-agent: *
Disallow: /forums/calendar.php

Sure enough, the next time the Googlebot came through it ignored /forums/calendar.php and didn’t use up ridiculous amounts of bandwidth indexing something that need not be indexed.

I can’t blame the Googlebot though. It was just doing its job. The fault goes to the creators of the calendar addon. What they should have done was add a rel="nofollow" to all the links in the calendar. You can add a nofollow tag to individual links to prevent Googlebot from crawling them. Google started using the nofollow tag as a method of preventing comment spam back in 2005.

Google Reported Attack Site

Google Reported Attack Site

I’m sure some of you must have seen this warning when you tried to visit my site. Fear not, I have fixed the problem. There was an old file on my domain that had a link to a site that was defined as “malicious” by Google, so they basically added my entire domain to the watch list. I removed the file and, after asking Google to check my site again using Google’s Webmaster Tools, they removed my domain from the list.

So, how did I find the few pages (among thousands of files on my site) that contained a link to the malicious site Google was blocking me for? I logged into my site via SSH and ran a command like the following:

for i in `find . -name "*.ht*"` ; do echo $i; cat $i | grep 195\.2\.252; done

This basically searched every single .htm or .html file inside my public_html directory and returned anything that contained the IP address I was looking for. Whenever there was a match, the filename that preceded the output was the offending file. I’m sure there’s a more elegant way of doing this, but hell, I just wanted to fix the problem!

Although this was annoying to deal with, it made me feel good that Google is actually keeping track of these things and, with the help of Firefox, is warning people of such sites. Site owners must be vigilant in fixing such problems or they risk losing loads of traffic from Google (and from visitors with Firefox).

Switching to suPHP; What a Mess!

When one of my users reported problems deleting files he had uploaded using a PHP script, I quickly discovered all the files being uploaded were owned by the user running the web server: nobody. This meant only the root user could delete those files.

Apache suEXEC is commonly used to resolve this problem. It allows Apache to run as the user who owns the domain being accessed. This way, files created by PHP would be owned by the user owning the site instead of the default nobody user.

However, Apache suEXEC only works if you’re using CGI as the PHP handler. The PHP5 handler on my server was set to use CGI, but I have PHP4 configured as the default PHP version and it was configured to use DSO. When I tried changing PHP4 to use CGI as the handler, most of the domains on my server displayed this:

Warning: Unexpected character in input: ‘’ (ASCII=15) state=1 in /usr/local/cpanel/cgi-sys/php4 on line 772
Warning: Unexpected character in input: ‘ in /usr/local/cpanel/cgi-sys/php4 on line 772
Warning: Unexpected character in input: ‘ in /usr/local/cpanel/cgi-sys/php4 on line 772
Warning: Unexpected character in input: ‘ in /usr/local/cpanel/cgi-sys/php4 on line 772
Parse error: syntax error, unexpected T_STRING in /usr/local/cpanel/cgi-sys/php4 on line 772

OK, that looks like a problem with cPanel. I don’t have time to debug cPanel’s problems.

suPHP, like suEXEC, is used to run Apache as the user who owns the domain. I decided to try recompiling Apache and PHP with suPHP enabled to see if that would fix the problem.

File Ownership Hell

suPHP worked, except now the sites using PHP sessions were trying to access stored session data in /tmp/ that was owned by the user nobody! So I deleted all the session data and that allowed the PHP sites to create new session data with file ownership of the user owning the domain.

But then I tried accessing my WordPress admin page and started getting permission denied errors in /wp-content/cache/. Same problem: the cache files that had been created before I enabled suPHP were owned by the user nobody and now the user who owns my domain couldn’t access them. A quick chown -R raamdev:raamdev /wp-content/cache/ fixed that problem.

Yeah, I could simply chown -R [user]:[user] /home/[user] for each of the users on the server, but there’s something about running a recursive command on files I’ve never seen, and know nothing about, that makes me uncomfortable.

More suPHP Limitations

I was beginning to worry that this was going to be more difficult than simply enabling suPHP and I wondered how many other sites I’m hosting could have similar problems. I tried accessing one of the high priority sites I’m hosting and discovered it was broken and displaying an “Internal Server Error”.

After a little research, I discovered that you cannot use php_value directives in .htaccess files with suPHP. The .htaccess file included with (created by?) Joomla! contained this at the bottom:

#Fix Register Globals
php_flag register_globals off

I already knew register_globals was turned off in the global PHP configuration, so I simply commented out that line and the site started working again.

Conclusion

It was at this point that I concluded it was too risky to just blindly enable suPHP while hosting over 50 domains, many of which I am not at all familiar with what’s being used or hosted. I will need to take the time to carefully crawl through all the sites making sure their .htaccess files don’t contain anything that might disrupt suPHP and then confirm all the sites are still working properly.

Lesson learned: Setup suPHP before you’re hosting 50+ domains.

Google Autocomplete for Search

I just noticed the main Google page now has autocompletion for the search box:

Google Autocomplete for Search

The feature, called Google Suggest, has been in the Labs for awhile. It “graduated” to the main front page almost exactly one week ago.

This is going to make it easy and lots of fun to check the most popular search term for a particular topic!

Gmail: Temporary Error (502)

GMail 502 Error

Looks like only some Google servers are experiencing this error; my other Gmail account works fine.

Using CURL to Upload Files via POST to Amazon S3

A few months ago I wrote a post about creating Amazon S3 HMAC Signatures without PEAR or PHP5. One of the things I was using that PHP script for was to feed the necessary information to a bash script hosted on a remote machine. The bash script was to upload a file via POST to Amazon S3 using the information provided.

Since CURL was already installed on the remote machine, I wanted to use that to do the actual uploading. I found very little help on the net regarding how to do this with CURL so here you go:

eris:~ raam$ curl \
-F "key=screenshots/current_screenshot.jpg" \
-F "acl=public-read" \
-F "AWSAccessKeyId=2EO6H8MX1X8YWEA0V432" \
-F "Policy=eyAiZXhwaXshdGlvbpI6ICIyMDA4LTErLTAxVDtyOjAwOjAwLjAsMFoiLAogICJjb25kaXRpb25zPjogWwoJeyJidWNrZXQiOiAiczNwaG90b3MubW9hcHAubmV0IiB9LAogICAgWyJzdGFydHMtd2l0aCIsICIka2V5IiwgIkxpdmVTaG90cy8iXSwKICAgIHsiYWNsIjogInB1YmxpYy1yZWFkIiB9LAoJWyJlcSIsICIkQ29udGVudC1UeXBlIiwgImltYWdlL2pwZWciXSwKICBdCn0K" \
-F "Signature=20uh08kU75ADHL49NyhYRgZW8BY=" \
-F "Content-Type=image/jpeg" \
-F "file=@current_screenshot.jpg" \
http://screenshots.ekarma.net

Keep in mind this assumes the current_screenshot.jpg file is in your current directory.

My Notes from The Last HOPE

Here are my notes from The Last HOPE. I started taking notes late, so unfortunately I don’t have notes from all the talks I attended.

Ghetto IDS and Honeypots
* An Evening with Berferd
* Low interaction honeypots: Nepenthes, honeyd, Honeytrap
* Monitor both Honeyd and Nepenthes with Prelude IDS

Monitoring Snort
* SGUIL
* BASE
* SnortSnarf

Remember, tcpdump (a common packet sniffer) writes data in pcap format which ngrep, WireShark, or Snort can process.

Kevin Mitnick - Featured Speaker
* Flowroute + Asterisks can be used to unmask Caller ID (I tested Mitnick’s setup by calling his phone… my blocked number showed up!)

PenTest Labs Using LiveCDs by Thomas Wilhelm
* de-ice.net
* BackTrack, Slax

PenTesting from Firefox URLs:
* isecom.org/osstmm/
* owasp.org/index.php/Main_Page/
* csrc.nist.gov/publications/PubsSPs.html
* vulnerabilityassessment.co.uk/Penetration Test.html
* centralops.net
* nmap-online.com
* hackerwhacker.com (similar to GRC)

Remember, use TOR when doing active tests!

More useful URLs:
* gdataonline.com/seekhash.php
* passcracking.com
* hash.insidepro.com
* md5this.com
* gdataonline.com
* us.md5.crysm.net
* md5.rednoize.com
* milw0rm.com
* freerainbowtables.com
* netcraft.com

Pen Testing the Web with Firefox

Firefox Extensions:
* FireCat
* ExploitMe (XSS-Me, SQL Inject-Me, Access-Me)
* Tamper Data
* Passive Recon
* Add N Edit Cookies
* Firebug
* HackBar
* Web Developer
* xssed.com

Using Firefox as a Front-End: Proxies
* Tor Button
* Paros Proxy
* SPIKE Proxy
* Burp Proxy

Web Frontends
* Metasploit
* FastTrack
* Inprotect (web interface for Nessus and Nmap)
* BASE (web front-end for Snort)

Use Firefox profile manager to install different selections of extensions to help with memory concerns.

FEBE (Firefox Environment Backup Extension)
CLEO (Compact Library Extension Organizer)
OPIE (Import/Export extension preferences)

Places/Things to hack “safely”
* OWASP WebGoat Project
* PwnOS (VMWare image, requires forum login)
* Your own VMWare lab

Identification Card Security: Past, Present, Future

The Complete Amature - ID Making Operating Guide by Doug Farre

* Epson Stylus R800 photo printer
* Laminator
* Dye cutter
* Magnetic stripe encoder
* Custom rubber stamp (simonstamp.com)
* Black light
* Scanner
* Signature pad
* Photoshop
* brainstormidsupply.com

Minimal needed materials:
* Laser Teslin
* Laminates
* Pearl-Ex pigment powders
* Ultraviolet pigment powder
* Transparent base

(Get these from practicingperfection.7p.com. That site is down as of right now, so you need the guy’s email address to contact him.)

Documentation on ID security can be found at idsysgroup.com.

Books to Read
* 1491: New Revelations of the Americas Before Columbus
* Hackers: Heroes of the Computer Revolution
* The Art of Intrusion: The Real Stories Behind the Exploits of Hackers, Intruders & Deceivers

Random URLs:
* foodhacking.com
* hackerspaces.org
* telephreak.org

LiquidWeb Dedicated Server Support Rocks!

A rouge mail server started using my server to send tons of spam messages. After checking a few obvious things (rouge scripts on my server sending spam, users sending the spam, etc), I immediately submitted a ticket to the data center, LiquidWeb. Within 30 seconds, D. Walters responded to the ticket:

Hey Raam,

I’m logging into your server right now to check things out. If you’re
still logged in, feel free to follow my work with this command:

screen -x dwalters

Regards,
D. Walters

I was already logged into the server, so I typed screen -x dwalters and sure enough, I instantly saw what he was doing on the server (I never knew this was possible with screen). I watched as he did various things, including installing a custom script that he wrote to help handle spam on server.

After a minute or two, he started typing something in the terminal that didn’t look like any command I had ever seen:

web:~ root# Hey Raam, are you there?

Since I was attached to the same terminal as him, I was able to type back. Over the next 20 minutes we spoke back and forth several times and exchanged geeky jokes. I asked him a couple of questions and he showed me example commands that I could run to glean useful information from the exim logs.

The name D. Walters was familiar to me, as he had responded to several of my LiquidWeb tickets in the past. He was familiar with my technical abilities and knew that I was Linux savvy, so he invited me to watch what he was doing. He trusted that I wouldn’t foolishly try typing in the terminal thereby interrupting what he was doing.

Dealing with someone familiar is important as it brings a feeling of trust to the situation. I compare the feeling to that of my auto mechanic; he lets me stay in the garage while he works on my truck. I stay out of the way and in return I get to stand under the truck, walk around the garage, and watch as he goes about his work. I simply wouldn’t be able to do that if I went to a Chevy dealership.

The response time at LiquidWeb is second to none. I can always get someone technically able on the phone, 24/7. That person is always within walking distance to my physical server on the rack. Add those things to my recent experience and I can honestly say, LiquidWeb dedicated server support rocks!

Amazon Http/1.1 Service Unavailable

This can’t be good for business:

Amazon HTTP Service Unavailable

I tested the website from a remote computer in Europe, on an entirely different ISP, and I get the same error.

Firefox 3 Bug: Warn me when closing multiple tabs

When I started using the beta version of Firefox 3, I quickly discovered a bug (which remains in RC1): Even though I had enabled the “Warn me when closing multiple tabs” option (Preferences -> Tabs), Firefox did not give me any warning when I accidentally pressed Cmd+Q. It would just quit without a prompting me, even if I had 15 tabs open!

In Firefox 2, enabling “Warn me when closing multiple tabs” option would cause this prompt to appear whenever I pressed Cmd+Q:

Firefox 2 Warn on Close

I searched Bugzilla@Mozilla for an open bug regarding this problem and quickly found Bug 422040 - Quit Firefox 3 beta 4 does not give “closing multiple tabs” warning. I commented about my own experience regarding this bug and further confirmed its existence in Firefox 3 RC1.

Finally, Paul O’Shannessy explained in comment #24 how the warn on close functionality works in Firefox 3:

Do you have the start up behavior to restore tabs & windows from last time?
If so, when you quit (cmd-Q) the dialog regarding save session will not show
and Firefox will quit. Session will be restored upon starting Firefox.

This used to bug me until I thought about it more. Perhaps a dialog confirming
that you intended to quit is in store for this case, but that would be a
different bug. On the plus side, if you hit cmd-Q by accident your session
should restore.

So basically, if you want to be warned when closing multiple tabs in Firefox 3, you need to make sure your “When Firefox starts” option (Preferences -> Main) is set to “Show my home page” and not “Show my windows and tabs from last time”. Setting it to the latter prevents the warning dialog when using Cmd+Q (however, you will get the warning if you try to close Firefox by pressing the X icon with your mouse).

To further confuse things, the warning dialog that comes up has a “Save and Quit” button. This button saves and restores your tabs the next time Firefox starts, which overrides your “When Firefox starts” setting of “Show my home page”.

Firefox 3 Warn on Close

Talk about inconsistent behavior. Even though this bug seems to be limited to Mac OS X, I really hope it gets fixed in the final release. But if it doesn’t get fixed, I’m glad it’s at least possible to get the warning dialog when pressing Cmd+Q and that you can choose to “Save and Quit”, even if it means making silly changes to the “When Firefox starts” option.