Security Tip: Validating Array Inputs

[Tip#42] Validating single values is easy, but what about arrays?

Security Tip: Validating Array Inputs
ℹ️
This is part of my series on the Top 10 Security Issues discovered during my Laravel Security Audits, as of April 2023.
This is #10 - Insufficient Input Validation

A common excuse for not validating inputs is complexity.

When building a complicated interface, it’s easy to get overwhelmed by the number of inputs your passing around, and then adding in arrays - and nested arrays - just bumps up the complexity significantly.

As a developer, I totally get it. I’ve done the same! But as a security person, and a hacker, I see opportunities to inject stuff! 😈

When attacking a form (during an audit), I specifically go looking for nested array inputs, and then see what I can inject into them. I look for sensitive columns, such as users.admin, and see what it’ll accept. Nested and related models are gold for this, as they are often blindly synced in batch, rather than carefully checked individually.

So how should you validate array inputs?

There are a few options, depending on what you need to do. Let’s take a look at each in turn.

  1. array validation rule.
    It allows you to specify which fields must be present in the input array.

    $input = [
        'user' => [
            'name'  => 'Frodo Baggins',
            'sword' => 'Sting',
            'ring'  => true,
        ],
    ];
     
    $request->validate([
        'user' => 'array:name,sword,ring',
    ]);.
  2. Simple dot-notation for nested values.
    Like elsewhere in Laravel, you can use dot-notation to traverse arrays, and assign unique rules to each array item. This is a great approach for ensuring each value is properly validated.

    $input = [
        'user' => [
            'name'  => 'Frodo Baggins',
            'sword' => 'Sting',
            'ring'  => true,
        ],
    ];
     
    $request->validate([
        'user.name'  => 'required|string',
        'user.sword' => 'nullable|string',
        'user.ring'  => 'required|boolean',
    ]);.
  3. Wildcard dot-notation for nested arrays.
    When dealing with arrays of items nested under a key, you can use the `*` wildcard to easily validate the keys within the array items.

    $input = [
        'users' => [
            ['name' => 'Frodo Baggins', 'sword' => 'Sting', 'ring' => true],
            ['name' => 'Gollum', 'sword' => null, 'ring' => false],
        ],
    ];
     
    $request->validate([
        'users.*.name'  => 'required|string',
        'users.*.sword' => 'nullable|string',
        'users.*.ring'  => 'required|boolean',
    ]);.

🥷
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!
🕵️
When was your last security audit or penetration test? Book in a Laravel Security Audit and Penetration Test today!