Start learning free

LESSON 68 OF 173 · BACKEND: APIS WITH A DATABASE

Search Products Safely

Practice

Clients often want to search instead of listing everything: /products?name=Mug. The part after the ? is the query string. A parameter string? name in the route's function reads it: ASP.NET Core fills it from the query string, and it is null when the request has no name.

Never build SQL by gluing a visitor's text into it. With "... WHERE name = '" + name + "'", the name x' OR '1'='1 turns the query into WHERE name = 'x' OR '1'='1', which is true for every row. That is SQL injection: the visitor's text becomes part of your SQL, and the same trick can read or change data they should never touch. Even an honest name like Ana's mug breaks the glued query.

A placeholder like $name fixes it: the text travels separately, as a parameter of the command, and the database only ever compares it as a value. For example, on a route that searches a table books:

var cmd = db.CreateCommand();
cmd.CommandText = "SELECT title FROM books WHERE author = $author";
cmd.Parameters.AddWithValue("$author", author);
GET /products?name=Mug           →  200  [{"id": 1, "name": "Mug", "price": 12, "category": "kitchen", "stock": 10}]
GET /products?name=Gift card     →  200  [{"id": 8, "name": "Gift card", "price": 50, "category": null, "stock": 999}]
GET /products?name=x' OR '1'='1  →  200  []
GET /products?name=Ana's mug     →  200  []
GET /products                    →  200  [… all 8 products …]

Your task: GET /products now takes an optional name. Without it, answer every product, as before. With it, answer only the products with exactly that name, passing the name through a $name placeholder.


Assignment
Follow the Coding Tutorial to run the right query for the name, or for no name.


Hint
Use name == null to tell a request without a name apart from one with a name. In the search, the name goes in with cmd.Parameters.AddWithValue, never inside the SQL string.


STEP 1 OF 5
    Ctrl + Enter to check