f in x
SQL Injection Prevention in Laravel and MySQL with Query Builder, Eloquent, and Safe Raw SQL
> cd .. / HUB_EDITORIALE
Analisi dei dati e metriche

SQL Injection Prevention in Laravel and MySQL with Query Builder, Eloquent, and Safe Raw SQL

[2026-06-06] Author: Ing. Calogero Bono

Have you ever seen a contact form that sends raw user input straight into a hand-written SQL query? We have. And every time a client hands us a site built with raw queries without parameter binding, our first thought is: “One single quote is all it takes to bring down the whole database.”

SQL Injection is the oldest web vulnerability, yet it remains the most insidious — one slip and your data is gone. In Laravel, the tools to prevent it are built-in. You just need to use them properly.

We at Meteora Web have seen exposed servers and stolen data because of unprotected queries. In this guide we show you exactly how to avoid it, with copy-paste-ready code.

Why SQL Injection Still Works

An SQL Injection attack occurs when user input is concatenated directly into a query. The attacker inserts an escape character (e.g., a single quote) and alters the query’s logic.

Vulnerable example:

$email = $_POST['email'];
$query = "SELECT * FROM users WHERE email = '" . $email . "'";
$result = mysqli_query($conn, $query);

If the user enters admin' --, the query becomes:

SELECT * FROM users WHERE email = 'admin' --'

And the attacker logs in as admin without knowing the password.

Laravel eliminates this problem if you use its stack correctly. But you can still write dangerous code if you drop into raw SQL without parameters.

Three Levels of Protection in Laravel

1. Query Builder: The Safest and Fastest

Laravel’s Query Builder uses prepared statements under the hood. Values are sent separately from the query structure, making it impossible to alter the logic.

$users = DB::table('users')
    ->where('email', $request->input('email'))
    ->first();

No matter what the user types, binding renders it harmless. This works for where, insert, update, delete.

Watch out for whereRaw and orderByRaw: If you must use raw queries, always pass parameters via associative array.

// SAFE
$users = DB::table('users')
    ->whereRaw('email = ?', [$request->email])
    ->get();

// EVEN SAFER with named parameter
$users = DB::table('users')
    ->whereRaw('email = :email', ['email' => $request->email])
    ->get();

2. Eloquent ORM: Native Protection with Mass Assignable Attributes

Eloquent extends security through $fillable and $guarded, but queries are always prepared.

$user = User::where('email', $request->email)->first();

Pitfalls to avoid: Don’t use firstOrFail or find with unsanitized input if you rely on implicit casting. Laravel still protects you, but get used to passing scalar variables.

For whereIn or whereBetween, use arrays:

$users = User::whereIn('id', $request->input('ids', []))->get();
// If ids is not an array, Laravel throws an exception or uses empty.

3. Raw SQL with DB::statement and DB::select: Binding Saves the Day

Sometimes you need pure SQL for performance (e.g., complex reporting). Always use DB::statement or DB::select with parameters.

DB::statement('UPDATE users SET points = points + ? WHERE id = ?', [$points, $userId]);

Never write:

DB::statement("UPDATE users SET points = points + {$points} WHERE id = {$userId}");
// INJECTION! If $userId is "1; DROP TABLE users--" you lose everything.

Real Cases We’ve Seen

One client had a custom report built with raw queries concatenating JSON input. We rewrote everything with binding in minutes. Result: faster queries (binding allows MySQL to cache execution plans) and zero vulnerabilities.

Another case: an e-commerce site with dynamic filters. They used whereRaw without binding to sort by price. One character could expose the entire orders table. We fixed it with orderByRaw('price ?', [$direction]).

We at Meteora Web have also recovered a backup after an SQL Injection attack on a third-party website. The database was exposed with all client data. Lesson: security is not an afterthought — it’s a development baseline.

Common Mistakes Even in Laravel

  • Using DB::raw without bindingDB::raw is for raw SQL fragments. If you concatenate variables, you lose protection.
  • Ignoring validation — Even with binding, malformed input can cause errors or logic bypasses. Always validate type, format, and length.
  • Not protecting stored procedures — If you call MySQL stored procedures, use prepared statements there too.
  • Forgetting dynamic orderByorderBy('column', $direction) is safe only if $direction is controlled (e.g., 'asc' or 'desc'). Never accept arbitrary input for the column name.

Verify That Your Queries Are Safe

You can enable Laravel’s query log to see prepared statements in action. Turn it on during development:

DB::enableQueryLog();
$users = User::where('email', $request->email)->get();
dd(DB::getQueryLog());
// You'll see 'bindings' => [':email' => '...'] and query with ? placeholders

Also, use tools like Laravel Security Checker or RIPS for automated scans. We recommend periodic penetration testing.

In Summary — What to Do Right Now

  1. Audit all raw queries in your code: search for DB::raw, whereRaw, selectRaw, orderByRaw. Convert to binding immediately.
  2. Always use DB::statement with associative arrays for complex raw queries.
  3. Enable robust validation on input fields using Laravel’s validate or FormRequest.
  4. Check query logs in development to verify binding.
  5. Run a security test with tools like sqlmap in staging to simulate attacks.

SQL Injection isn’t a problem if you code with security in mind from the first character. Laravel gives you all the tools — use them. If you have an old PHP project to audit, we’re here to help.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored

> MW_JOURNAL

> READ_ALL()