Friday, April 20, 2007

Tracking users with Basic Auth

Update: Amit Klein, being the very thorough expert that he is, pointed out that method #2 below has previously been used in the wild. And that #3 might not actually work in IE, RSnake was experiencing some strange caching issue he and Amit are working our the details on.

Thanks to RSnake for helping me test this one. Some users configure their web browsers to block cookies entirely or least for certain websites (like banner providers). They’re attempting to protect their privacy, imagine that. Anyway, there seems to be a way to track users with Basic Auth instead of cookies. Here’s a walk through of the concept:

1) User visits a websiteA where they are blocking its cookies.

2) websiteA delivers a web page with some JavaScript code that silently forces the browser to Basic Auth to the web server with a specific username and password. Think of the u/p as nothing more than a session ID as the web server will authenticate anything sent.

Depending on the browser, either of these methods below could work and will cache the u/p.

Firefox Only
<* img src="http://session:ID@website/">


Firefox or Internet Explorer

function forceBasic Authentication() {
var req = null;
var req = new XMLHttpRequest();
if (!req) { req = new ActiveXObject("Msxml2.XMLHTTP"); }
if (!req) { req = new ActiveXObject("Microsoft.XMLHTTP");}'GET', 'http://website/', false, 'Session', ‘ID’);

Internet Explorer Only

function forceBasic Authentication() {
var req = null;
var req = new XMLHttpRequest();
if (!req) { req = new ActiveXObject("Msxml2.XMLHTTP"); }
if (!req) { req = new ActiveXObject("Microsoft.XMLHTTP");}'GET', 'http://website/', false);
req.setRequestHeader("Authorization", "Basic nQzw==");

3) Once the browser is authenticated, after receiving a 401, the browser will cache the u/p and send it with each subsequent HTTP request. The benefit of this method is that there is no way to block Basic Auth forced in this way and the user receives no standard Basic Auth pop-up.


Ambush Commander said...

I've actually seen this behavior before (having authenticated elsewhere on the website, when accessing a Subversion repository you'll be prompted because the credentials that were automatically sent were invalid), although I never thought it could be adapted to track users. Great stuff.

kL said...

Using cache for tracking is better and even works cross-domain (unless user has Firefox extension that limits it to single domain).

Create cachable javascript file that contains predefined unique number and sends it home whenever it's executed.

Kishor said...

I have a few questions
1. Will this last after browser is closed?
2. If no, how is it different than having session ids in url etc? (One advantage would be that you dont have to take care of adding session id to every url, but is there any other reason?)


Ory said...


I think kishor has a point - why not just use session IDs in the URL?

Sure, it might require some URL rewriting, but most webapp frameworks support it anyway (e.g. ASP.NET cookieless mode).

Regardless, this is really cool...

Jeremiah Grossman said...

Kisho and Ory:

1) No, creds are lost upon browser close.

2) This wasn't so much about that you couldn't track a user another way (URL Sessions), but that you technically could using Basic Auth. This is something we can add to the browser hacking arsenal that we might able to use in a combo attack later.

PortSwigger said...

Hey Jeremiah, nice post.

I think you can also make the point that using HTTP auth for user tracking is a little more reliable than the other methods mentioned.

If an application places a token within the URL or a form field, then it will be resubmitted as the user clicks through the app. However, if they make requests outside of the app's own navigation (for example, by typing in different URL, or following a link on a third-party site) then the token will be lost.

In this situation, using HTTP auth will still work because once credentials are set the browser resubmits them in each subsequent request, regardless of its origin (as with cookies).

Anonymous said...

How do i retrieve the Session ID values on subsequent page loads? For example, if I force basic authentication at my home page, and later want to retrieve the Session ID on a checkout page. How do i do that?

Jeremiah Grossman said...

That Session ID is stored in the Authorization header the web browser sends. Depending on your environment, there are a number of ways to get access to that information.

Anonymous said...

Thanks for the tip i will look at blocking auth requests and i already block etags via a proxy server i am working on but for love nor money can if find where FF or IE stores the etags on the client.