The day a thousand apps stool still
I noticed some weeks ago that Twitter’s OAuth implementation didn’t appear to be verifying signatures. I knew this because I purposefully set an invalid access token which was accepted unconditionally. I thought this was odd, but as a newbie to OAuth I was just happy that my app was working, so I filed the problem at the back of my mind under “deal with it if it becomes a problem”. Today (the week I release by beloved TwitBlock app) it very suddenly became a problem.
It seems that eventually they decided to fix the security hole, except they did it without telling anyone. In their defence this needed to be done quickly, and they were only going to be implementing what we all believed was already in place, namely the well-documented OAuth standard. The problem was that many people, including myself have publicly released apps that could never have been fully tested.
The damage was already done, i.e. broken apps in the public domain; but the clean up operation didn’t go well either. At the time of writing, no warning has been posted on status.twitter.com. The first we all knew about the change was broken apps, and disappointed users. A few threads popped up on this Google Group where devs banged their heads together to work out what was wrong with their code libraries. In my case I eventually tracked down the bug: The main cause of my broken library was that I was signing the full request URL complete with query string. This is incorrect, as section.9.1.2 demonstrates. A bug that, if I’d been able to test properly in development, would not have made it into production.
Twitter’s response
Although I’ve not seen an official response, I did see a post on the afore-mentioned Google Group by one of the Twitter API developers. He admitted that they did not approach the situation as they should, but this post may have been deleted because I can no longer find it. I shall post it if I find it again.
URL encoding bug
Another bug (which was not actually the main problem) is that PHP’s rawurlencode function doesn’t quite fit the bill. OAuth parameter encoding implements RFC3986 whereas PHP’s rawurlencode function implements RFC1738… the difference is that PHP will encode the “~” character. A simple fix is to retro decode the offending character, as follows:
function oauth_urlencode( $str ){ return str_replace('%7E', '~', rawurlencode($str) ); }