Category: Tips & Tricks
2010
11.21

Warning

The method of preventing CSRF attacks described in this post is now considered to be insufficient. A comment on this post links to more details about an attack that circumvents it.

The Setup

About two weeks ago, I discovered a CSRF vulnerability on a well-known website (I won’t mention it by name). The vulnerability itself was fairly mundane: one of their scripts lacked tokens or any other form of CSRF protection. I sent in an email to their security team to let them know about it and went on my way.

The other day, I looked back at the website to see if the vulnerability had been fixed: it had. I also discovered that the vulnerability had been fixed using a method I had never thought about before. The website used “standard” HTTP headers, rather than a random token in the query string, to ensure that the request was from a valid source.

How does it work?

The browser makes an AJAX request. In that request, a special header is set: X-Requested-With. This header is non-standard, but it’s used by many JavaScript libraries (i.e., jQuery, Prototype).

On the server side, the server validates the request to make sure the header exists in the request. If it doesn’t, the request is rejected. If you’re using a library like jQuery, this is the only bit of code you have to implement.

Why does it work?

To add the header to a request within the context of the browser (which is what you need to do to pull off a CSRF attack properly), the attacker needs to use XMLHttpRequest. However, thanks to same-origin restrictions, XMLHttpRequest doesn’t allow you to make an AJAX request to a third party domain by default. Thus, it’s not possible for an attacker to forge a request with a spoofed X-Requested-With header.

There are, of course, some caveats:

  1. You need to use AJAX requests to take advantage of this protection: regular GETs and POSTs don’t allow for header manipulation.
  2. If your site allows some form of cross-domain AJAX requests (see https://developer.mozilla.org/en/http_access_control for more details), this won’t protect you.
  3. Like any other form of CSRF protection, it can be circumvented under certain circumstances. An insecure crossdomain.xml file, for instance, will still allow malicious Flash applets to go wild on your website.

It is, however, much better than using the Referer header. ;-)

2010
11.14

I spent quite a bit of time last night configuring Pidgin, my new IM client. A large portion of that time was focused on one particular issue: getting a Google Talk account (when using Google Apps for Your Domain) to play nicely with Pidgin. From looking at the search results for “google talk pidgin”, it looks like I’m not the only one with that problem. Since I did eventually get everything set up, I decided to document the process here in the hopes it might help someone else. :-)

The first thing I did was check out Google’s official documentation (http://www.google.com/support/a/bin/answer.py?hl=en&answer=49147). I followed the instructions, but when I went to connect I encountered a variety of error messages. “Read error”, “Unable to connect”, “Server closed the connection”, etc. The documentation was clearly missing a step.

Next, I stumbled on some references in the Google Talk help forum to a post on the Ubuntu forums (http://ubuntuforums.org/showthread.php?t=499906). The post talks about changing some advanced configuration settings for the account. After a little bit of trial and error with the settings, I found a combination that works.

How to configure the account

You’ll want to load the “Modify Account” screen (assuming the account is already created). That can be accessed by going to the Accounts menu, selecting the account in question, and choosing “Edit Account” from the list of options.

Once the screen is loaded, click on the Advanced tab. You’ll be presented with a number of different configuration options. The following list contains the settings I updated, along with what I set their values to. Any omitted settings can be left as-is.

  • Connection security: Use old-style SSL
  • Connect port: 5223 (this was the default, but it’s worth repeating here)
  • Connect server: talk.google.com

With those changes in place, Pidgin connected to Google Talk without complaint. :-)

Note: These steps were performed on Pidgin 2.7.5. If you’re using a different version of Pidgin, your steps may be slightly different, your form fields may have different names, etc.

2010
08.13

A recent Java project (replacing a very slow Excel spreadsheet) required me to do some calculations involving money. The issues involved in using floating point arithmetic to handle monetary calculations are well documented (Google it if you don’t believe me) so, as any smart Java programmer would do, I started writing my program using BigDecimal to represent the money.

Unfortunately, when I started checking my results, I found that my answers wouldn’t match up with Excel’s!

Worse, my answers didn’t match up with ones done directly on the data source that both Excel and my program were using to get data!

And even worse, Excel’s answers exactly matched those from the data source.

I was astonished. How, I asked myself, could floating point arithmetic beat arbitrary precision so badly?

Then, suddenly (and by suddenly I mean a half-hour later), it hit me.

BigDecimal has a notion of something called “scale.” The scale corresponds to the number of digits to the right of the decimal place. Thus, the scale determines how accurate BigDecimal calculations will be. If the scale is set too low, the precision is lowered.

As it turned out, the scale on all of my BigDecimals was a measly four digits (I was following good practice by using BigDecimal’s String constructor, and my data source returned numbers with four decimal places). For comparison, printing out my double at any given point would give me \~10 digits. As soon as I set the scale properly, the calculations became accurate and my BigDecimal formulas started working the way I expected them to. :)

2010
08.04

My laptop was infected by a virus recently. My Java installation was out of date (so much for auto-update!) and I browsed to a page containing malicious advertisements which downloaded a virus. I immediately stopped what I was working on and cleaned off the computer. After spending a couple hours on it, I was reasonably certain the virus was gone.

Unfortunately, I started getting messages from Symantec Auto-Protect telling me that it had found an infected file in my temporary directory. Since that was where the infection started, I began to worry that I hadn’t completely eliminated the virus. So I rebooted into safe mode, re-scanned, etc. Nothing found!

This was puzzling, but I figured I would just continue to work like normal. Unfortunately, today the popups from Auto-Protect started again. Originally I thought that one of the sites I was visiting was infected: however, when I closed the site in question, the alerts continued. Finally, I Googled, hoping to find a solution. All I knew was that the filename was random-ish (DWH*.tmp) and that Norton was describing the virus as Trojan.gen (Norton’s generic term for “a trojan horse of some kind”).

Luckily, I ended up stumbling upon my answer. It was written by a Symantec employee in response to a topic about the issue:

http://www.symantec.com/connect/forums/generic-trojan-dwhtmp-temp-folder

The DWH files are temp files that are created by our process called defwatch.exe. These files are quarantined threats that we pull out of quarantine to scan during a quick scan. This usually happens when new defs are applied…What we have seen in most cases, is the indexing service, or some other real-time scanner is touching the file and then auto-protect is re-scanning it.

So, mystery solved! The files I was seeing where actually quarantined versions of the viruses I had eliminated earlier. A couple clicks to empty my quarantine and I wasn’t getting any more alerts. Very satisfying. :-)

2010
08.02

In case anyone else is interested in counting requests per IP without the use of some scary sed/awk, here’s a combination of shell commands that I found very useful:

1
grep 'text' /path/to/access.log | cut -d' ' -f1 | sort | uniq -c | sort -r

It breaks down like this:

  1. You grep for whatever string you’re interested in inside your access log. You could want to find a certain path, a certain user-agent, etc. The grep could really be replaced by any command, so long as the result is lines from a standard Apache access log.
  2. The result is piped to cut, which splits each line and grabs the first field (the IP by default)
  3. The result is piped to sort, which sorts the result, putting identical IPs next to each other. Remember, one line corresponds to one request.
  4. The result is piped to uniq, which groups sorted IPs together. The -c option causes uniq to also return the number of lines containing the IP. This is important since we’re interested in frequency
  5. Finally, we pipe the result through sort one more time, which sorts the results by their frequency. The -r option puts the most frequent IPs at the top.

Kudos to http://blogs.law.harvard.edu/djcp/2009/04/how-to-extract-uniq-ips-from-apache-via-grep-cut-and-uniq/, which pointed me in the right direction to begin with.

Note: As Frank mentions in the comments, this tip applies equally as well to other web servers (eg: lighttpd, Nginx) when they’re using their default log format. In fact, the basic principles can be applied to just about any data: you don’t have to be looking at IPs in an access log. The cut/sort/uniq/sort chaining should work well no matter what kind of textual data you’re looking at!

2010
07.22

In no particular order, this is a list of my favorite Firefox extensions. They make my browsing experience awesome and I wouldn’t trade them for anything in the world. :)

  1. Live HTTP Headers. I’ve had this extension for years and it has proved invaluable time and time again. I use it for debugging and security testing. Very simple, very easy to use, very powerful.
  2. Firebug. This one is important for anyone doing web design/development. It’s just an absolutely awesome tool. I can’t imagine ever having developed HTML/CSS without it. It even comes with its own extension system, which I haven’t taken advantage of but which looks incredible.
  3. Web Developer Toolbar
  4. User Agent Switcher. Both #3 and #4 are made by the same developer. These were two of the first extensions I ever installed. I keep using them because of how useful they are for debugging and testing.
  5. View Source With. Allows me to view HTML in my favorite Windows text editor, Notepad2
  6. BugMeNot. While it has grown less useful over the years (sites are getting better and better at banning their accounts), it’s always a good time-saver to have. It can’t hurt! :-)

There are definitely a couple developers who I need to donate to. BRB! :-P

2010
07.11

About a year ago, a couple friends and I were working on a PHP-based web application for one of our classes. The web application needed to take in input from another website (the school’s calendar system), which provided data in CSV format. As a result, I became very familiar with PHP’s (lack of) CSV parsing functionality and there’s one tip in particular that I think is worth sharing.

PHP has two main functions for parsing CSV data: fgetcsv and str_getcsv. fgetcsv complements other functions like fopen, fsockopen, etc: it’s used to read data from files, similar to fread. In contrast, str_getcsv works on strings: there’s no file I/O necessary. This is much more appealing than having to perform low-level reads/writes to fetch data (especially when your data is coming from another website). Unfortunately, it only exists in PHP >= 5.3.0.

So, for our project, we took in data from a website (using an HTTP client class provided by the PHP framework we were using) and stored it in a string. But since we didn’t have PHP 5.3, we needed to turn the data into a file if we wanted to read from it. Luckily, a comment on PHP.net alerted us to a convenient way to “work around the issue”:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
// Assume this variable contains CSV data from some external source, stored as a string
$my_csv_text = get_csv_from_internet();

// Open a memory "file" for read/write...
$f = fopen('php://temp', 'r+');
fwrite($f, $my_csv_text);
rewind($f);

while (($data = fgetcsv($f)) !== FALSE)
{
    // do stuff with the data!
}

What the code does is it takes advantage of a PHP 5.1 feature: the ability to write to a temporary location (which, according to the PHP docs, is stored in memory unless the data is above a certain size, at which point it’s written to disk instead). That allows for the data to be read without any messy cleanup. The only disadvantage is slightly higher memory usage, since the entire CSV file is stored twice (once as a string in PHP, once after being written to php://temp). In addition, anyone using an earlier version than 5.1 or who wants to avoid the memory usage can just write to a file instead: the code should work exactly the same.

2010
07.03

Recently at work, one of my friends ran into a problem trying to integrate the Google Visualization API and jQuery. His setup seemed fairly straightforward and it didn’t seem like there would be any problems. He wanted the user to select an option from a dropdown box. That selection would trigger a GET request to fetch some JSON (using the getJSON function of jQuery) from his web server. The result of the request would be passed via getJSON’s callback to Google Visualizations, which would then display some nice charts.

Sounds easy, right?

Unfortunately, when he tested his code in Firefox, the visualization he wanted never showed up. All he saw was an empty iFrame where his chart should have been (Google Visualizations draws certain types of charts using SVG in iFrames).

Puzzled, he started debugging. He quickly confirmed that the proper calls to draw the visualization were being made. Yet somehow, they were just returning an empty iFrame instead of one filled with data. Even more puzzling, his code worked fine when he tested it in Google Chrome, Safari, etc: Firefox was the only browser where it failed!

His next step was to try replacing his chart code with Google’s example code, thinking that maybe the issue was with his data. Amazingly, that chart also failed to display properly! However, it also led him to another discovery: the chart drawing would only fail if it was attempted from within getJSON’s callback function. If the chart was drawn before or after, it would work correctly.

Finally, after several people spent hours wrestling with the problem, one of our fellow employees came up with a solution. He created a closure that would call the correct Javascript functions to draw a graph. Then, he passed that closure to setTimeout with a timeout of 0. It was a fairly elegant workaround: using setTimeout avoided the weird scoping issue (we still don’t understand what the problem was!) and the closure allowed the data to be passed out of the troublesome callback and to the Google Visualization classes. Definitely not the cleanest solution, but very welcome after several hours of wrestling with the problem!

2010
06.26

Disclaimer: This is not about hiding or disabling Wordpress’s automatic update notices. If that’s your goal, there are a series of wonderful plugins which will do the job for you (for core, plugin, and theme updates). Instead, this is about making it physically impossible for administrators of a Wordpress installation to use the install/update functionality in the backend of the site.

If you choose to do this, you must make sure to keep up-to-date with new releases and update your site as soon as new versions are released. If you fail to do so, you run an increased risk of security vulnerabilities or performance issues with your website/blog.

Short version

If you create a file named upgrade in the wp-content directory, Wordpress will be unable to download any new plugins/themes or upgrade existing code.

Long version

I needed to figure out how to disable the automatic update feature because I was using SVN to store/deploy the code for several clients’ Wordpress installations. I had a central SVN repository for each client which I pushed changes to and which the websites pulled their code from. Unfortunately, Wordpress deletes all traces of the existing plugin when upgrading; that means the .svn directory inside each plugin’s directory would also be removed, breaking the working copy. If I didn’t disable the feature, someone with administrative access could break the website’s working copy just by upgrading a plugin.

As it so happened, I found an easy solution. All I had to do was create a 0 byte file at wp-content/upgrade (removing the directory with that name if it exists). That directory is used by Wordpress as temporary space when installing/updating code. Placing a file there instead causes the process to fail; Wordpress has no place to store files temporarily. It is sort of a hack, but it works well enough for my purposes; I don’t have to modify the Wordpress core, I just have to create a single file.

2010
06.21

Note: This post was originally written in August 2009

Earlier in the summer, I found myself needing to set up my laptop to work with the wireless network in my house. Part of that process involved setting up printing: I needed to print over the network to an HP Officejet K80, which was connected via USB to a desktop in another part of the house. The printer was all set up to be shared over the network and I didn’t anticipate running into any issues.

Of course, I did run into issues. Every time I tried to set up the printer in Vista, Windows would display an error message with the ominous title “Windows cannot connect the printer.” The error message also referenced a cryptic error code, 0x000006bb. Searching for that error code yielded a few results but no solid answers. Even after a lot of fiddling with related areas like workgroups and firewalls, the error continued.

Eventually, I realized what was causing the issue. When I used the Add Printer wizard, I was selecting “Add a network, wireless or Bluetooth printer” because the printer was being shared over the network. However, the Officejet uses a USB connection; even though it is technically acting as a network printer, Vista needs a “local port” to print to! That meant I needed to select “Add a local printer” and create a new “local port” for my networked printer.

Vista's Add Printer Screen, with the correct option (Add a local printer) highlighted.

Vista’s Add Printer Screen, with the correct option (Add a local printer) highlighted.

Once I discovered the right option to choose, setting up the printer was a snap. All I had to do was create a new local port pointing to the shared printer (\COMPUTERNAME\PrinterShareName) and voila! My computer was finally connected to my printer.

Choose a Printer Port selection screen, with the "Create a new port" option selected.

Choose a Printer Port selection screen, with the “Create a new port” option selected.

So, to recap, if you’re trying to get a Vista computer to connect to a networked USB printer, be sure to add it as a local printer, not a network printer. :)