Even though Laravel is one of the most secure and developer-friendly PHP frameworks, SQL injection vulnerabilities can still creep in when developers use raw queries or fail to validate user input properly. Understanding how these attacks happen and how Laravel helps you prevent them is key to building safe, production-grade applications.
In this article, we’ll break down SQL injection in Laravel — from understanding the vulnerability to exploring real-world code examples, and finally, seeing how to secure your application using Laravel’s built-in features.
What Is SQL Injection?
SQL Injection (SQLi) is a web security vulnerability that allows an attacker to interfere with the queries your application makes to its database. It usually occurs when user input is directly embedded into SQL queries without proper sanitization or parameter binding.
In short, it’s when untrusted input meets unescaped SQL.
Example of a vulnerable query
php
// Example: Unsafe query using raw input
$user = $_GET['username'];
$password = $_GET['password'];
$result = DB::select("SELECT * FROM users WHERE username = '$user' AND password = '$password'");
If an attacker enters this in the login form
vbnet
Username: admin' --
Password: anything
The resulting SQL query becomes
sql
SELECT * FROM users WHERE username = 'admin' -- ' AND password = 'anything'
The comment symbol (--) causes the rest of the query to be ignored, bypassing authentication entirely.
How Laravel Handles Database Queries
Laravel provides three primary ways to interact with the database:
Eloquent ORM: A model-based approach.
Query Builder: Fluent, chainable methods.
Raw SQL Queries: Direct execution of SQL strings.
While the first two methods are inherently protected against SQL injection through automatic query parameter binding, the third is risky if not handled properly.
For example
php
// Safe: Laravel automatically binds parameters
$user = DB::table('users')->where('email', $email)->first();
vs
php
// Unsafe: Manually concatenating variables into SQL
$user = DB::select("SELECT * FROM users WHERE email = '$email'");
The second example opens the door to injection attacks.
A Simple SQL Injection Example in Laravel
Let’s simulate a basic scenario where a developer uses user input in a raw SQL query.
php
public function search(Request $request)
{
$term = $request->input('query');
// ❌ Vulnerable query
$results = DB::select("SELECT * FROM products WHERE name LIKE '%$term%'");
return view('search-results', ['results' => $results]);
}
If an attacker types
vbnet
' OR 1=1 --
The resulting SQL becomes
sql
SELECT * FROM products WHERE name LIKE '%%' OR 1=1 -- %'
This retrieves every product in the database, regardless of the intended filter.
Exploiting the Vulnerability
In a real-world scenario, attackers can use this weakness to:
Extract sensitive data (users, passwords, tokens).
Modify or delete records.
Gain administrative access.
Chain attacks to perform remote code execution in extreme cases.
For example
vbnet
' UNION SELECT email, password FROM users --
This can dump confidential user data if the query isn’t parameterized.
How Laravel Prevents SQL Injection
Laravel provides automatic query parameter binding for Eloquent and Query Builder queries.
Example
php
// ✅ Safe query using bindings
$results = DB::select("SELECT * FROM products WHERE name LIKE ?", ["%$term%"]);
Here, Laravel escapes the user input before executing the query — preventing any malicious SQL from being executed.
Eloquent ORM provides even safer abstractions:
php
// ✅ Safe and elegant
$results = Product::where('name', 'LIKE', "%$term%")->get();
This approach uses parameter binding under the hood, completely eliminating the risk of injection.
Best Practices to Prevent SQL Injection in Laravel
Use Eloquent ORM or Query Builder
Avoid raw SQL queries whenever possible.
php
$users = User::where('role', 'admin')->get();
Always Use Parameter Binding
If you must use raw queries:
php
DB::select('SELECT * FROM users WHERE id = ?', [$id]);
Validate and Sanitize User Input
Laravel’s validation system ensures only expected data reaches your queries.
php
$request->validate([
'email' => 'required|email|max:255',
]);
Avoid Dynamic Column or Table Names
Never pass user input into database schema identifiers.
php
// ❌ Dangerous
$table = $_GET['table'];
DB::select("SELECT * FROM $table");
// ✅ Safe
DB::table('products')->get();
Use Laravel’s Query Logging in Development
Enable query logging to inspect generated SQL and detect unsafe patterns:
php
DB::enableQueryLog();
Laravel’s Built-In Tools for Safer Queries
Query Builder Escaping: Automatically escapes input values.
Eloquent ORM: Provides safe abstractions for CRUD operations.
Validation Middleware: Filters and sanitizes incoming data.
CSRF Protection: Mitigates injection through form submissions.
Mass Assignment Protection: Prevents overwriting sensitive model attributes.
Visualizing SQL Injection Flow
Below is a simple conceptual illustration to understand how safe vs unsafe queries behave:
Unsafe Query Flow
css
[User Input] ---> [Concatenated SQL] ---> [Database Executes Malicious Command]
Safe Query Flow
css
[User Input] ---> [Parameter Binding] ---> [Escaped SQL Execution]
Testing for SQL Injection
You can test for injection vulnerabilities using tools like:
Always perform such testing in development or staging environments only — never on production systems.
Real-World Security Tips
Keep Laravel and its dependencies updated.
Disable detailed error reporting in production (APP_DEBUG=false).
Regularly audit raw queries across your codebase.
Use a Web Application Firewall (WAF) to block malicious inputs.
Conduct periodic penetration testing and code reviews.
Conclusion
SQL injection remains one of the oldest yet most exploited vulnerabilities on the web. Even with Laravel’s built-in protections, developers must remain cautious when using raw SQL or handling untrusted input.
By leveraging Laravel’s ORM, query bindings, and validation mechanisms — and following secure coding practices — you can effectively eliminate this threat from your application.