Adventures in base64, or: How not to design your confirmation links

I recently applied for a room at a student housing complex. After finishing up my online application, I got a confirmation link. I clicked it, checked that everything was fine, and closed it. I then reopened it because the URL had caught my eye. Slightly modified for privacy:

https://[...]/xyz.html?ID=MTIzNHxEb2V8Sm9obnwxOTkwLTAxLTAxCg==

Now, if you’ve been playing around with “dd if=/dev/urandom | base64” like I have, you will see the patterns that imply a base64 encoded string in this URL. So, I quickly copied the ID and decoded it (as I said, I changed the ID around a bit to avoid disclosing personal information).

$ echo MTIzNHxEb2V8Sm9obnwxOTkwLTAxLTAxCg== | base64 -d
1234|Doe|John|1990-01-01

Sooo. Well, that’s not very secure, is it? Give me a confirmation link which I know how to build and only have to guess one part of, which is probably automatically incrementing. I can work with that. But then again, why would I want to fake registrations to a student housing complex? Let’s keep digging.

$ echo "1235|Doe|John|1990-01-01" | base64
MTIzNXxEb2V8Sm9obnwxOTkwLTAxLTAxCg==

Let’s enter that changed ID into the URL, and…

Your Application could not be confirmed: The application was not found in the database (Applicant_ID:1235, Surname:Doe, Name:John, DateOfBirth:1990-01-01)

Oh well. Okay, let’s at least check for Cross-Site scripting, maybe we can find something…

$ echo "<script type="text/javascript">alert('xss');</script>|Herp|De Derp|1337-42-42" | base64
PHNjcmlwdCB0eXBlPSd0ZXh0L2phdmFzY3JpcHQnPmFsZXJ0KCd4c3MnKTs8L3NjcmlwdD58SGVycHxEZSBEZXJwfDEzMzctNDItNDIK

Enter this into the URL, and…

Your Application could not be confirmed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'text/javascript'>alert('xss');' and Surname='Herp' and DateOfBirth='1337-' at line 1

Yikes. At this point, I backed the hell off, because we have some pretty strict laws about this stuff in Germany. SQL injections are not to be taken lightly, so I quickly whipped up an eMail to the organization and explained the problem to them. I received a lot of silence, and after a few days, I called them up and asked if they had received my mail. They had, and were working on it.

Almost two weeks passed, and the hole was still there, so I called again and asked for the person in charge of the homepage. A brief talk revealed that they had passed the issue on to their vendor, who was, appearently, not very good with providing delivery dates. I asked if I could release this blog entry, and they asked for more time, which I agreed to.

Today, I received an eMail stating that the hole had been fixed. I double checked it, and appearently, it was indeed fixed. I also received permission to release this blog entry. Appearently, the system was in use not only at this specific institution, but also in some other institutions (who have been notified about the need to update, I hope).

All in all, except for the long periods of waiting, it was a pleasent experience. The people at the institution were friendly and understood the dangers of the issue. If everyone would react as quickly and professionally as they did, the web would probably be a more secure place. The reaction time of the vendor could be improved though, taking almost a month to deliver a fix for a critical security issue that could be fixed by changing approximately one line of code is not acceptable.