Site icon DirgaRaj Lama

How to Prevent SQL Injection in Laravel (Real‑World Examples)

How to Prevent SQL Injection in Laravel

SQL injection remains one of the most dangerous web vulnerabilities, but Laravel’s built‑in tools make it surprisingly simple to prevent SQL injection in Laravel—if you know the right practices. In this guide, we’ll show you real‑world attack scenarios and how to block them using Eloquent, query builders, and parameter binding. By the end, your database will be safe from even the most crafted malicious inputs.

What Is SQL Injection and Why Laravel Developers Must Care?

SQL injection occurs when an attacker manipulates a query by inserting unintended SQL commands through user inputs. For example, a login form that uses string concatenation can be tricked with ' OR '1'='1. Without proper protection, an attacker can steal, alter, or delete your entire database.

Laravel, by default, protects you—but only when you use its tools correctly. The most reliable way to prevent SQL injection in Laravel is to always use Eloquent ORM or the query builder with parameter binding. Let’s see exactly how.

Real‑World Example 1: The Dangerous Raw Query (What NOT to Do)

Imagine you’re building a search feature for a products table. A junior developer might write:

// VULNERABLE CODE – DO NOT USE
$search = $_GET['search'];
$results = DB::select("SELECT * FROM products WHERE name LIKE '%$search%'");

An attacker could enter ' OR '1'='1' OR name LIKE '% as the search term, turning the query into:

SELECT * FROM products WHERE name LIKE '%%' OR '1'='1' OR name LIKE '%%'

This returns every product in the database. Worse, they could use '; DROP TABLE products; -- to delete your table.

How to fix it: Never use raw concatenation. Laravel’s query builder automatically uses parameter binding. The safe version:

$search = request('search');
$results = DB::table('products')->where('name', 'like', '%'.$search.'%')->get();

Laravel escapes $search automatically. This is your first step to prevent SQL injection in Laravel.

For an external reference on SQL injection patterns, check out OWASP SQL Injection Prevention Cheat Sheet.

Real‑World Example 2: Using Eloquent Safely with User Input

Many developers think using Eloquent alone is always safe. But there’s a catch. Look at this example:

// SAFE – Eloquent with parameter binding
$email = request('email');
$user = User::where('email', $email)->first();

This is safe because Laravel binds $email as a parameter. However, if you ever use DB::raw() inside an Eloquent query, you reintroduce the vulnerability.

The right way to prevent SQL injection in Laravel with Eloquent:

For dynamic column names (e.g., sorting by user input), never concatenate. Instead, validate against a whitelist:

$allowedColumns = ['id', 'name', 'email'];
$sortBy = in_array(request('sort'), $allowedColumns) ? request('sort') : 'id';
$users = User::orderBy($sortBy)->get();

Learn more about secure coding in our Laravel security best practices guide.

Real‑World Example 3: Raw Queries Done Right

Sometimes you need raw SQL for complex reports. Laravel provides a safe way using parameter binding. For example, a dangerous raw query:

// STILL VULNERABLE
DB::select("SELECT * FROM users WHERE age > $age");

Fix it with bindings:

// SAFE – using named bindings
$age = request('age');
$users = DB::select("SELECT * FROM users WHERE age > :age", ['age' => $age]);

Laravel escapes the :age placeholder automatically. You can also use positional ? bindings:

$users = DB::select("SELECT * FROM users WHERE age > ?", [$age]);

This method lets you prevent SQL injection in Laravel even when writing custom SQL.

For deeper technical details on PDO bindings (which Laravel uses internally), see PHP PDO Prepared Statements.

Real‑World Example 4: Defending Against Second‑Order Injection

Second‑order injection happens when data is stored safely (e.g., via Eloquent) but later used unsafely in a raw query. Consider this:

$name = User::find($id)->name; // This value is clean in DB but contains dangerous SQL
DB::statement("DELETE FROM logs WHERE username = '$name'"); // VULNERABLE

Even though the input was originally safe during insertion, the second query concatenates it. Always treat any data from the database as potentially unsafe when used in a raw SQL context.

Fix: Use parameter binding again:

DB::statement("DELETE FROM logs WHERE username = ?", [$name]);

This is a subtle but critical lesson in how to prevent SQL injection in Laravel comprehensively.

Bonus: Validation and Input Sanitization (Defense in Depth)

While parameter binding stops SQL injection, you should still validate inputs. Laravel’s validation rules like stringmax, and regex reduce unexpected characters. For example:

request()->validate([
    'search' => 'string|max:100|regex:/^[a-zA-Z0-9 ]+$/',
]);

However, remember: validation is not a substitute for parameter binding. It’s an extra layer. Always bind parameters.

For a complete checklist, read our Laravel input validation and security tutorial.

Summary: Your SQL Injection Prevention Checklist

To prevent SQL injection in Laravel in every project, follow these rules:

Conclusion

SQL injection is entirely preventable when you leverage Laravel’s built‑in protections. By always using parameter binding, avoiding raw concatenation, and validating inputs, you can confidently prevent SQL injection in Laravel even in complex, real‑world applications. Start by auditing your existing queries today—your database will thank you.

Secure your Laravel app today and stay one step ahead of attackers. For more details or personalized help, feel free to contact me.

Exit mobile version