Security Tip: Retrieving Request Values

[Tip#40] Let's complete the set of request input helpers and their security implications

Security Tip: Retrieving Request Values

Laravel’s Request object (Illuminate\Http\Request) includes a number of methods for extracting user input. Last week we covered some individual methods, and this time we’re covering the array/collection methods.

// $request->validate()
public function validate(
    array $rules = [], 
    array $messages = [], 
    array $attributes = []
): array;

My favourite approach: Validates the user input and, if successful, returns an array of only validated input. Usable in most scenarios. 😉


// $request->only()
public function only($keys): array;

Returns only the input values with the specified keys as an array. This allows you to be sure that only the values you intend are returned, avoiding mass-assignment vulnerabilities.

Note that if an input value doesn’t exist, it won’t be included in the output array.


// $request->collect()
public function collect($key = null): \Illuminate\Support\Collection;

Returns the user input in a Laravel Collection, rather than an array. Note this carries the same risks as the all() method.

You can also specify a single key via the $key parameter to cast that specific input value as a Collection, or an array of keys to return a Collection with only those keys from the user input.


// $request->all()
public function all($keys = null): array;

Use this method carefully!

Let’s get this one out of the way first. Without the $keys parameter, it returns all of the user submitted data, regardless of what it is. This makes it trivial to introduce mass-assignment vulnerabilities into your apps.

If you pass the $keys parameter, it will return an array with every key you specify, even if it doesn’t exist in the user input. The value will be null instead. This makes the method safe to use, although I would suggest using only() instead so the parameters cannot be accidently removed.


// $request->except()
public function except($keys): array;

The opposite of only($keys). Blocks specific input values from being returned in an array. I can see a use in some situations, but like any blocklist, you need to be careful of what could be included.


As I said above, all of these methods are available on the Illuminate\Http\Request object, which you’ll typically have injected into your Controller action, or you use the Request Facade, or request() helper function:

use \Illuminate\Http\Request;

public function edit(Request $request): View
{
    $data = $request->validate([...]);
    // ...
}
use \Illuminate\Support\Facades\Request;

public function show(Model $model): View
{
    $data = Request::only([...]);
    // ...
}
public function show(Model $model): View
{
    $data = request()->collect([...]);
    // ...
}

My Recommendations

Every use case is different, but my recommendation is to only use validate($rules), only($keys), and collect($keys).

This gives you full control over the user input you accept into your app, significantly reducing the possibility of mass-assignment vulnerabilities (which is incredibly easy to do).

Between those three methods, and the ones we looked last time, you should have the flexibility you need to safely work with user input.

Bonus Methods

As an bonus, there are two more methods you can use:

public function query($key = null, $default = null);
public function post($key = null, $default = null);

These will only input values only from the query string or post data respectively. This allows you to control exactly where the data comes from, if that’s important for your application.


🕵️
When was your last security audit or penetration test? Book in a Laravel Security Audit and Penetration Test today!
🥷
Looking to dive deeper into Laravel security? Check out Practical Laravel Security, my hands-on security course that uses interactive hacking challenges to teach you about how vulnerabilities work, so you can avoid them in your own code!