Time to reset some passwords

About once a year, I accidentally type my password into the user name field on a login form and click submit. Immediately, I realize what I did as I see my password sitting there, mocking me in plain text from the user name field. I did that today, and it's time to go reset my passwords. For those of you who aren't involved in web development, let me explain why.

Nearly everything you do online gets logged, but it's standard security practice to filter passwords out of the logs. However, filtering passwords doesn't help much when you type your password in a user name field. Here's an example log of what I just did:

Processing UserSessionsController#create (for at 2010-02-21 11:43:21) [POST]
  Parameters: {"user_session"=>{"user_name"=>"Th1s1sMyP@ssw0rd","password"=>"[FILTERED]"}}
[User Load (0.4ms) incorrect user_name or password - user not loaded]

Processing UserSessionsController#create (for at 2010-02-14 11:43:53) [POST]
  Parameters: {"user_session"=>{"user_name"=>"nathan","password"=>"[FILTERED]"}}
  [User Load (0.4ms) "user_name"=>"nathan" loaded]

As you can see, on my first login attempt, the log contains my password as the user name, my IP address, a time stamp, and a note that the login failed. On my second login attempt, the log contains my real user name, my filtered (correct) password, my IP address, a time stamp, and a note that the login succeeded.

Given that these two events happen within a minute of each other and come from the same IP address, a savvy attacker with access to the logs (or an unscrupulous systems administrator) could determine that my password is Th1s1sMyP@ssword just by looking at the logs. That attacker could also create a script that would prune the logs for all failed logins from the same IP address that are followed by successful logins within some short time period from a different user name. If the attacker slurped the logs into a database (and had a SQL-wielding DBA wife to help with his queries like I do), he could use a query like this:

select success.ip, success.user_name as user_name, fail.user_name as password
    (select *
        from login_attempt f
        where f.success = false
    ) fail
inner join
    (select *
        from login_attempt s
        where s.success = true
    ) success
on fail.ip = success.ip
and success.datetime between fail.datetime and date_add(fail.datetime, interval 5 minute)

on a login_attempt table with columns: ip, datetime, user_name, and success to give him possible user name/password combinations.

Luckily, I only have to change the passwords for 2 or 3 accounts, but many web users carry a single password with them to every site, leaving them broadly exposed if an attacker discovers the password for a single account.