
Tóm tắt nhanh
- XSS (Cross-Site Scripting) — Laravel tự động escape nhưng cẩn thận với raw() và unescaped output
- SQL Injection — Dùng Eloquent/Query Builder, tránh raw queries
- CSRF — Laravel có sẵn @csrf, đừng bao giờ bỏ qua
- Mass Assignment — Khai báo fillable/guarded đầy đủ
- IDOR — Luôn kiểm tra ownership với Policies
- Weak Passwords — Enforce password policy mạnh
- Session Hijacking — Regenerate session after login
- Command Injection — Không dùng user input trong shell commands
- XXE — Disable XML external entities
- Debug Mode in Production — Không bao giờ để debug=true trên production
Bạn có biết Laravel cung cấp strong security defaults, nhưng chính bạn có thể vô hiệu hóa chúng không? [1] Trong bài này, mình sẽ chỉ bạn 10 lỗi bảo mật phổ biến nhất và cách phòng tránh hiệu quả.
XSS – Cross-Site Scripting
XSS xảy ra khi attacker inject malicious script vào web application để chạy trên browser của người dùng khác. Laravel tự động escape tất cả output trong Blade templates, nhưng có cách bạn có thể bypass điều này [2]. Để hiểu rõ hơn về Authentication và Authorization trong Laravel, hãy đọc bài Authentication & Authorization trong Laravel nhé!
Cách tấn công:
// Không an toàn nếu $comment chứa script
<div>{{ $comment }}</div>
// Nếu attacker inject: <script>alert('hacked')</script>
// Script sẽ chạy trên browser của tất cả users xem comment nàyPhòng tránh:
- Luôn dùng double braces:
{{ $variable }}— tự động escape - Tránh dùng {!! !!}: Chỉ dùng khi thực sự cần và đã validate kỹ
- Dùng e() helper:
{{ e($variable) }}— explicit escape
// ĐÚNG - Tự động escape
<p>{{ $user->name }}</p>
// SAI - Không an toàn
<p>{!! $user->name !!}</p>
// ĐÚNG - Explicit escape nếu cần
<p>{{ e($user->bio) }}</p>Tip: Laravel’s
{{ }}tự động chạyhtmlspecialchars()— đây là first line of defense against XSS!

SQL Injection
SQL Injection xảy ra khi attacker thao túng SQL queries để truy cập trái phép vào database. Dù Laravel’s Eloquent ORM bảo vệ bạn, raw queries vẫn là điểm yếu [2].
Không an toàn:
// NGUY HIỂM - User input trực tiếp trong query
$posts = DB::select("SELECT * FROM posts WHERE user_id = " . $request->user_id);An toàn:
// AN TOÀN - Dùng parameterized queries
$posts = DB::select("SELECT * FROM posts WHERE user_id = ?", [$request->user_id]);
// AN TOÀN - Dùng Eloquent
$posts = Post::where('user_id', $request->user_id)->get();
// AN TOÀN - Dùng Query Builder với bindings
$posts = DB::table('posts')->where('user_id', $request->user_id)->get();Thú vị nhỉ! Nhiều vụ hack lớn trên thế giới xảy ra vì SQL injection — đây là lỗi có thể prevent dễ nhất!
CSRF – Cross-Site Request Forgery
CSRF lừa user đã authenticate thực hiện actions không mong muốn. Laravel có built-in CSRF protection — đừng bao giờ bỏ qua nó [3].
Thêm CSRF vào forms:
<form method="POST" action="/delete-post">
@csrf
<input type="hidden" name="id" value="{{ $post->id }}">
<button type="submit">Delete</button>
</form>Hoặc dùng Blade directive:
<form method="POST" action="/transfer-money">
@csrf
<!-- Form fields -->
</form>Verify trong code:
// Laravel tự động verify CSRF token cho POST/PUT/DELETE
// Nhưng có thể exempt nếu cần (API, webhooks)
Route::post('/webhook', [WebhookController::class, 'handle'])
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
Mass Assignment
Mass assignment cho phép attacker gán giá trị cho các fields không được phép. Laravel cung cấp fillable/guarded nhưng nhiều dev vẫn bỏ qua [4].
Nguy hiểm:
// User có thể truyền thêm is_admin = true
$user = User::create($request->all());Phòng tránh:
class User extends Model
{
// Chỉ những fields này mới được mass assign
protected $fillable = ['name', 'email', 'password'];
// Hoặc dùng guarded - chặn các fields nhạy cảm
protected $guarded = ['is_admin', 'role', 'id'];
}Đây là lỗi mình thấy phổ biến nhất ở các dự án mới — đừng bao giờ bỏ qua fillable/guarded!
IDOR – Insecure Direct Object References
IDOR xảy ra khi user có thể truy cập data của người khác bằng cách thay đổi ID trong URL.
Nguy hiểm:
// User A có thể xem profile của User B
Route::get('/profile/{id}', [ProfileController::class, 'show']);
// Controller không kiểm tra ownership
public function show($id) {
$profile = User::find($id);
return view('profile', compact('profile'));
}Phòng tránh:
// Dùng Policy
public function show(User $user) {
$this->authorize('view', $user);
return view('profile', compact('user'));
}
// Hoặc kiểm tra trực tiếp
public function show($id) {
$profile = User::findOrFail($id);
if (auth()->id() !== $profile->id) {
abort(403, 'Bạn không có quyền xem profile này');
}
return view('profile', compact('profile'));
}
Weak Passwords
Password yếu là con đường phổ biến nhất để account bị compromise.
Phòng tránh:
// Dùng Laravel's password validation
use Illuminate\Validation\Rules\Password;
$request->validate([
'password' => ['required', 'confirmed', Password::min(12)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised()],
]);Rules có nghĩa:
- letters(): Ít nhất 1 chữ cái
- mixedCase(): Cả hoa và thường
- numbers(): Ít nhất 1 số
- symbols(): Ít nhất 1 ký tự đặc biệt
- uncompromised(): Không nằm trong known password leaks
Mình khuyên bạn: Enforce password policy mạnh, đặc biệt cho admin accounts. 12+ ký tự là minimum!
Session Hijacking
Attacker có thể chiếm session của user để truy cập trái phép.
Phòng tránh:
// Regenerate session sau khi login
public function authenticated(Request $request, $user)
{
$request->session()->regenerate();
}
// Cấu hình session secure trong config/session.php
'secure' => env('SESSION_SECURE_COOKIE', true),
'http_only' => true,
'same_site' => 'strict',
Command Injection
Attacker có thể thực thi shell commands nếu bạn dùng user input trong exec() hoặc shell functions.
Nguy hiểm:
// NGUY HIỄM
exec('ping ' . $request->host);Phòng tránh:
// Dùng Process facade thay vì exec
use Illuminate\Support\Facades\Process;
$result = Process::run('ping -c 4 ' . escapeshellarg($request->host));
// Hoặc dùng Laravel's built-in networking
$response = Http::ping($request->host);Tip:
escapeshellarg()là temporary fix — tốt nhất là tránh hoàn toàn user input trong shell commands!
XXE – XML External Entities
XXE attack khai thác việc parse XML không an toàn.
Phòng tránh:
// Disable external entities khi parse XML
$xml = simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOENT);
// Hoặc dùng XMLReader với safe settings
$reader = new XMLReader();
$reader->open($url);
$reader->setParserProperty(XMLReader::VALIDATE, true);Trong Laravel, nếu dùng package để parse XML → kiểm tra documentation về security settings.
Debug Mode in Production
Để debug=true trên production = expose toàn bộ application secrets!
Cấu hình đúng:
// .env
APP_ENV=production
APP_DEBUG=false
// config/app.php
'debug' => (bool) env('APP_DEBUG', false),Đây là lỗi nghiêm trọng nhất! Debug mode hiển thị database credentials, API keys, stack traces — tất cả cho attacker [5].

Tổng kết
10 lỗi bảo mật này phổ biến nhưng có thể phòng tránh dễ dàng:
- XSS: Dùng
{{ }}thay vì{!! !!} - SQL Injection: Dùng Eloquent/Query Builder
- CSRF: Thêm
@csrfvào mọi form - Mass Assignment: Khai báo
$fillablehoặc$guarded - IDOR: Kiểm tra ownership với Policies
- Weak Passwords: Enforce password policy mạnh
- Session Hijacking: Regenerate session, dùng secure cookies
- Command Injection: Tránh user input trong shell commands
- XXE: Disable external entities
- Debug Mode:
APP_DEBUG=falsetrên production
Laravel cung cấp strong security defaults — đừng để vô hiệu hóa chúng! Với Authentication & Authorization, hãy đọc thêm bài Authentication & Authorization trong Laravel để biết thêm chi tiết.
Nếu bạn có câu hỏi → để lại comment nhé!
Nguồn tham khảo
- Benjamin Crozat – Laravel Security Best Practices 2026
- Umar Waqas – Laravel Best Practices for Secure Web Applications
- Laravel Official – CSRF Protection
- Laravel Official – Mass Assignment
- Nuffing – Security Blueprint for Enterprise Laravel
Các câu hỏi thường gặp
Laravel có bảo mật mặc định không?
Laravel cung cấp strong security defaults: CSRF protection, XSS escaping, password hashing, mass-assignment protection. Tuy nhiên, bạn có thể vô hiệu hóa chúng — hãy giữ chúng enabled!
Làm sao phòng XSS trong Laravel?
Luôn dùng Blade’s double braces {{ }} thay vì {!! !!}. Laravel tự động escape tất cả output trong {{ }}. Chỉ dùng {!! !!} khi thực sự cần và đã validate input kỹ.
SQL Injection có thể xảy ra trong Laravel không?
Có, nếu dùng DB::raw() hoặc nối chuỗi trực tiếp. Dùng Eloquent hoặc Query Builder với parameterized queries để an toàn.
IDOR là gì và cách phòng trong Laravel?
IDOR xảy ra khi user có thể truy cập data của người khác bằng cách thay đổi ID. Dùng Laravel Policies để kiểm tra ownership trước khi trả dữ liệu.
APP_DEBUG nên để giá trị gì trên production?
Luôn để APP_DEBUG=false trên production. True sẽ expose toàn bộ stack traces, database credentials, và secrets cho attacker.
Cần làm gì để bảo mật Laravel production?
10 điểm: APP_DEBUG=false, dùng HTTPS, enable rate limiting, enforce strong passwords, enable MFA, dùng Policies/Gates, validate all input, keep Laravel updated, run composer audit, và test security regularly.
