Các cuộc tấn công SQL Injection không may là khá phổ biến trong các ứng dụng web hiện đại và kéo theo những kẻ tấn công cung cấp dữ liệu đầu vào yêu cầu độc hại để can thiệp vào các truy vấn SQL. Hướng dẫn này bao gồm SQL injection và cách ngăn chặn nó cụ thể cho các ứng dụng Laravel. Bạn cũng có thể tham khảo Bảng thông tin ngăn chặn SQL Injection để biết thêm thông tin không dành riêng cho Laravel.
Theo mặc định, Eloquent ORM của Laravel bảo vệ khỏi việc đưa vào SQL bằng cách tham số hóa các truy vấn và sử dụng các liên kết SQL. Ví dụ: hãy xem xét truy vấn sau:
use App\Models\User;
User::where('email', $email)->get();
Đoạn mã trên kích hoạt truy vấn bên dưới:
select * from `users` where `email` = ?
Vì vậy, ngay cả khi $email
dữ liệu đầu vào của người dùng không đáng tin cậy, bạn vẫn được bảo vệ khỏi các cuộc tấn công SQL injection.
Laravel cũng cung cấp các biểu thức truy vấn thô và truy vấn thô để tạo các truy vấn phức tạp hoặc truy vấn cơ sở dữ liệu cụ thể không được hỗ trợ.
Mặc dù điều này là rất tốt cho tính linh hoạt, nhưng bạn phải cẩn thận luôn sử dụng liên kết dữ liệu SQL cho các truy vấn như vậy. Hãy xem xét truy vấn sau:
use Illuminate\Support\Facades\DB;
use App\Models\User;
User::whereRaw('email = "'.$request->input('email').'"')->get();
DB::table('users')->whereRaw('email = "'.$request->input('email').'"')->get();
Cả hai dòng mã thực sự thực thi cùng một truy vấn, điều này rất dễ bị chèn SQL vì truy vấn không sử dụng liên kết SQL cho dữ liệu đầu vào của người dùng không đáng tin cậy.
Đoạn mã trên kích hoạt truy vấn sau:
select * from `users` where `email` = "value of email query parameter"
Luôn nhớ sử dụng liên kết SQL cho dữ liệu yêu cầu. Chúng tôi có thể sửa mã trên bằng cách thực hiện sửa đổi sau:
use App\Models\User;
User::whereRaw('email = ?', [$request->input('email')])->get();
Chúng tôi thậm chí có thể sử dụng các ràng buộc SQL được đặt tên như vậy:
use App\Models\User;
User::whereRaw('email = :email', ['email' => $request->input('email')])->get();
Bạn không bao giờ được cho phép dữ liệu đầu vào của người dùng xác định tên cột được tham chiếu bởi truy vấn của bạn.
Các truy vấn sau có thể dễ bị chèn SQL:
use App\Models\User;
User::where($request->input('colname'), 'somedata')->get();
User::query()->orderBy($request->input('sortBy'))->get();
Điều quan trọng cần lưu ý là mặc dù Laravel có một số tính năng tích hợp sẵn như gói tên cột để bảo vệ khỏi các lỗ hổng SQL injection ở trên, một số công cụ cơ sở dữ liệu (tùy thuộc vào phiên bản và cấu hình) vẫn có thể dễ bị tấn công vì tên cột liên kết không được hỗ trợ bằng cơ sở dữ liệu.
Ít nhất, điều này có thể dẫn đến lỗ hổng gán hàng loạt thay vì chèn SQL vì bạn có thể đã mong đợi một tập hợp giá trị cột nhất định, nhưng vì chúng không được xác thực ở đây nên người dùng cũng có thể sử dụng các cột khác.
Luôn xác thực thông tin đầu vào của người dùng cho những trường hợp như vậy:
use App\Models\User;
$request->validate(['sortBy' => 'in:price,updated_at']);
User::query()->orderBy($request->validated()['sortBy'])->get();
Các quy tắc xác thực nhất định có tùy chọn cung cấp tên cột cơ sở dữ liệu. Các quy tắc như vậy dễ bị tấn công bởi SQL injection theo cách tương tự như SQL injection tên cột vì chúng xây dựng các truy vấn theo cách tương tự.
Ví dụ: mã sau có thể dễ bị tấn công:
use Illuminate\Validation\Rule;
$request->validate([
'id' => Rule::unique('users')->ignore($id, $request->input('colname'))
]);
Phía sau, đoạn mã trên sẽ kích hoạt truy vấn sau:
use App\Models\User;
$colname = $request->input('colname');
User::where($colname, $request->input('id'))->where($colname, '<>', $id)->count();
Vì tên cột được quyết định bởi đầu vào của người dùng, nó tương tự như việc đưa vào SQL tên cột.
You need to login in order to like this post: click here
YOU MIGHT ALSO LIKE