Start learning free

LESSON 99 OF 173 · BACKEND: USERS AND SECURITY

Don't Let Clients Set Everything

Practice

A sign-up sends a JSON body, and a client can put any keys in it, not only the ones your form asks for. If your code saves every key as a column, the client chooses what gets stored: "role": "admin" makes an admin, and "id": 1 tries to take the admin's id. This hole is called mass assignment.

The fix is an allowlist: a list of the keys a client may set. You build the new row yourself and copy only the keys on your list. Everything else in the body is ignored. Here is the idea for a review form:

var REVIEW_FIELDS = new List<string> { "stars", "text" };

var review = new Dictionary<string, object>();
foreach (var field in REVIEW_FIELDS) {
    if (Field(data, field) != null) {
        review[field] = Field(data, field);
    }
}

Then answer with what the database stored, not with what the client sent. Ana asks to be an admin and becomes a customer. Ben asks for id 50 and gets the next free id:

POST /register  {"email": "ana@example.com", "password": "secret123", "name": "Ana Pop", "city": "Cluj", "role": "admin", "id": 1}
  →  201  {"city": "Cluj", "email": "ana@example.com", "id": 2, "name": "Ana Pop", "role": "customer"}
POST /register  {"email": "ben@example.com", "password": "tea4two!", "id": 50, "role": "admin"}
  →  201  {"city": null, "email": "ben@example.com", "id": 3, "name": null, "role": "customer"}
POST /login  {"email": "ana@example.com", "password": "secret123"}
  →  200  {"token": "<token>"}
GET /me  (Authorization: Bearer <token>)
  →  200  {"email": "ana@example.com", "id": 2, "role": "customer"}
POST /products  {"name": "Desk", "price": 120}  (Ana's token)
  →  403  {"error": "Admins only"}

Your task: add the columns name and city to the users table and write the allowlist SIGNUP_FIELDS. In /register, build newUser from that list, add the password's hash, save it with InsertRow, read the stored row back and answer it with 201.


Assignment
Follow the Coding Tutorial to close the mass assignment hole in POST /register with an allowlist.


Hint
Loop over SIGNUP_FIELDS, not over data: then the loop never even meets "role" or "id". Copy a field only when Field(data, field) isn't null, so a missing name simply stays empty.


STEP 1 OF 12
    Ctrl + Enter to check