Find out what a stranger could do to the class wall
The class wall is open on purpose. The page only lets you paint squares in your own colour, but the page isn't what protects the data. The database rules are.
In this exercise you'll skip the page and talk to the database directly, the way anyone on the internet could. Then we'll switch on some rules and try again. By the end you should be able to answer two questions for any app: who should be able to read this data, and who should be able to write it?
Only do this to the class wall, and only in class. It's our database and you have permission. Doing the same thing to someone else's site without permission is illegal in most countries, including India.
Setup
- Open gyanl.com/wall and join with your name.
- Open DevTools and go to the Console tab. You'll type everything here.
- Paste this in and press Enter:
const DB = "https://rtdb-test-7f656-default-rtdb.asia-southeast1.firebasedatabase.app";
That's the database's address. It's in the page's code, in firebase-config.js, so anyone who looks can find it.
Firebase lets you reach any path in the tree as a URL. Add .json to the end of the path, like the API URLs from Lecture 5 - APIsLecture 5 - APIs
Homework Review
Let's look at your submissions!
Exercise - Figma to Code
Exercise - Unusual Interactions
Two kinds of website
There are 2 types of websites: static sites and dynam...:
| Path in the tree | URL |
|---|---|
wall |
DB + "/wall.json" |
wall/47 |
DB + "/wall/47.json" |
| the whole tree | DB + "/.json" |
You can read a URL with fetch, and write to it by adding a method: PUT replaces what's at a path, PATCH changes some of it, and DELETE removes it.
Round 1: no rules
The database is in test mode: anyone can read and write anything. Try each of these, and keep the wall open on the projector or on your phone to see what happens.
1. Read everything
await (await fetch(DB + "/.json")).json();
You get the whole database, not just what the page shows.
2. Paint a square without clicking it
await fetch(DB + "/wall/0.json", {
method: "PUT",
body: JSON.stringify({ colour: "#00ff00", name: "YOUR NAME" })
});
3. Paint as someone else
Change name to a classmate's name and paint a square. The leaderboard gives them the point.
4. Take the lead
const squares = {};
for (let i = 0; i < 100; i++) {
squares[i] = { colour: "#00ff00", name: "YOUR NAME" };
}
await fetch(DB + "/wall.json", { method: "PATCH", body: JSON.stringify(squares) });
One request, and you own 100 squares.
5. Break the page
Try writing things the page would never write:
- a colour that isn't a colour:
{ colour: "hello", name: "YOUR NAME" } - a name that's 500 characters long:
"a".repeat(500) - a square that doesn't exist:
/wall/99999.json - something that isn't part of the wall at all:
/graffiti.json
Watch what the page does with each one.
6. Erase
Delete one square:
await fetch(DB + "/wall/0.json", { method: "DELETE" });
Don't delete the whole wall. We'll do that once, together, at the end.
Round 2: with rules
Now I'll switch on these rules in the Firebase console:
{
"rules": {
"wall": {
".read": true,
"$square": {
".write": true,
".validate": "newData.hasChildren(['colour', 'name'])",
"colour": { ".validate": "newData.isString() && newData.val().matches(/^#[0-9a-fA-F]{6}$/)" },
"name": { ".validate": "newData.isString() && newData.val().length > 0 && newData.val().length <= 20" },
"$other": { ".validate": false }
}
}
}
}
Read them out loud:
"wall": { ".read": true }— anyone can read the wall. Nothing else in the tree is readable."$square": { ".write": true }— anyone can write to one square at a time.$squarestands for any key underwall..validate— every square must have acolourand aname. The colour must look like#ff4343, the name must be 1–20 characters, and no other fields are allowed.
Run all six attacks again, and fill in this table:
| Attack | Round 1 | Round 2 |
|---|---|---|
| Read everything | ||
| Paint a square without clicking | ||
| Paint as someone else | ||
| Take the lead with a script | ||
| Break the page | ||
| Erase a square |
Then answer these
- Which attacks did the rules stop, and which still work? For each one that still works, why can't these rules stop it?
- The rules can check what the data looks like, but not who sent it. Anyone can type any name. What would the database need to know about the person writing, to stop someone painting as you?
- Who should be able to read the wall, and who should be able to write to it? Answer for the wall as it is now, and again for a version where only students in this class can paint.
-
Would you ever want the same rules for a real product? Pick one of the Lecture 6 - localStorage and Databases#Project ideas project ideas Note does not exist
This note is has not been published (yet).
and write, in plain language, who should be able to read and write each part of its tree.
Things to notice
- The page was never the security. Everything you did in Round 1, the page had no say in. Hiding a button doesn't stop anyone. Only the database can say no.
- Rules can't know who you are without sign-in. To stop impersonation, people have to log in first. Firebase Authentication gives each person an ID, and rules can then say things like "you can only change squares you painted". That's also how you'd stop one person owning the whole wall.
- Open isn't always wrong. A wall anyone can paint is the point of this one. The mistake is leaving things open without deciding to.