The Endpoint Nobody Thought To Rate Limit

by Serguey Shinder

We had been through an assessment a few months earlier and had come out well. One of the items we were pleased about was login throttling. Too many failed attempts from the same place and the door closed for a while. It was tested, it was documented, and I remember the small satisfaction of a control that actually worked.

The attack did not go near the login form.

What it used instead was a small helper the sign-up flow called, the one that tells you an address is already registered so you get a useful message rather than a failure at the end of a long form. It answered in about forty milliseconds. It answered differently depending on whether the address existed. And it had no limit of any kind, because nobody had ever thought of it as a security surface. It was a convenience.

Somebody walked a list through it over a few nights at a polite two or three requests a second, well below anything our monitoring would have flinched at, and came away with a clean list of which addresses on that list had accounts with us.

Then they sent those people a very good email. Not a generic one. One that assumed, correctly, that the recipient was a customer, which is exactly the assumption that makes a phishing message believable.

We learned about it from support, from people forwarding a message and asking whether it was really from us. Not from an alert. Our alerting was watching the door we had decided mattered.

What I took from it is that we had protected the endpoint we imagined an attacker using. An attacker does not share our mental model of the system. They look for the cheapest question that returns information about somebody else's data, and a sign-up convenience check is very cheap indeed.

The habit that came out of it is a list, and it is not a list of login pages. It is a list of every endpoint whose response changes depending on data that does not belong to the person asking. A registration check. A password reset that says whether the account exists. A search that returns nothing versus forbidden. An invite flow. A public profile lookup. Any of those, answered quickly enough and often enough, is a way of reading our database one bit at a time.

Most of them do not need a hard block. A limit generous enough that no real person ever notices is usually enough, because the attack depends on volume.

The uncomfortable part is that every one of those endpoints exists because somebody was trying to be helpful. The useful error message and the enumeration oracle are the same feature, described by two different people.

– Serguey Asael Shinder

Leave a Reply