Skip to content
All articles

The View Counter That Let Anyone Write Anything

1 min read
securityfirestorepostmortem

A page view counter needs writes from readers who are not signed in. That requirement is reasonable. The first implementation was not.

The rule that looked fine

allow update: if request.auth == null;

The intent was "anonymous readers may bump the counter." What it says is "anonymous readers may replace the entire document." Title, body, published flag — all writable by anyone with the project id, which ships in your client bundle.

Pinning the write

Three conditions, all necessary:

allow update: if resource != null
  && resource.data.get('published', false) == true
  && request.resource.data.diff(resource.data).affectedKeys().hasOnly(['views'])
  && request.resource.data.views is int
  && request.resource.data.views == resource.data.get('views', 0) + 1;

hasOnly blocks extra fields riding along. The equality check blocks setting the count to an arbitrary number. The published check stops drafts being probed for existence.

The lesson

An allow rule grants everything it does not forbid. Write down what the operation is permitted to change, then encode exactly that — "who" is only half a rule, "what" is the other half.