Về nhiều câu trả lời hữu ích, tôi hy vọng sẽ thêm một số giá trị cho chủ đề này.
SQL tiêm là một cuộc tấn công có thể được thực hiện thông qua đầu vào của người dùng (đầu vào được điền bởi người dùng và sau đó được sử dụng bên trong các truy vấn). Các mẫu tiêm SQL là cú pháp truy vấn chính xác trong khi chúng ta có thể gọi nó là: truy vấn xấu vì lý do xấu và chúng tôi cho rằng có thể có một người xấu cố lấy thông tin bí mật (bỏ qua kiểm soát truy cập) ảnh hưởng đến ba nguyên tắc bảo mật (bảo mật , tính toàn vẹn, và tính sẵn sàng).
Bây giờ, quan điểm của chúng tôi là ngăn chặn các mối đe dọa bảo mật như các cuộc tấn công tiêm nhiễm SQL, câu hỏi đặt ra (làm thế nào để ngăn chặn một cuộc tấn công tiêm nhiễm SQL bằng PHP), thực tế hơn, lọc dữ liệu hoặc xóa dữ liệu đầu vào là trường hợp khi sử dụng dữ liệu đầu vào của người dùng bên trong truy vấn như vậy, sử dụng PHP hoặc bất kỳ ngôn ngữ lập trình nào khác không phải là trường hợp hoặc theo khuyến cáo của nhiều người hơn là sử dụng công nghệ hiện đại như tuyên bố đã chuẩn bị hoặc bất kỳ công cụ nào hiện đang hỗ trợ phòng ngừa tiêm SQL, xem xét các công cụ này không còn khả dụng nữa? Làm thế nào để bạn bảo mật ứng dụng của bạn?
Cách tiếp cận của tôi chống lại SQL tiêm là: xóa dữ liệu đầu vào của người dùng trước khi gửi nó đến cơ sở dữ liệu (trước khi sử dụng nó trong bất kỳ truy vấn nào).
Lọc dữ liệu cho (chuyển đổi dữ liệu không an toàn thành dữ liệu an toàn)
Hãy xem xét rằng PDO và MySQLi không có sẵn. Làm thế nào bạn có thể bảo mật ứng dụng của bạn? Bạn có ép tôi sử dụng chúng không? Còn các ngôn ngữ khác ngoài PHP thì sao? Tôi thích cung cấp các ý tưởng chung vì nó có thể được sử dụng cho biên giới rộng hơn, không chỉ cho một ngôn ngữ cụ thể.
- Người dùng SQL (giới hạn đặc quyền người dùng): hầu hết các hoạt động SQL phổ biến là (CHỌN, CẬP NHẬT, CHERTN), tại sao, tại sao lại cung cấp đặc quyền CẬP NHẬT cho người dùng không yêu cầu? Ví dụ: các trang đăng nhập và tìm kiếm chỉ sử dụng CHỌN, vậy thì tại sao lại sử dụng người dùng DB trong các trang này với các đặc quyền cao?
Quy tắc: không tạo một người dùng cơ sở dữ liệu cho tất cả các đặc quyền. Đối với tất cả các hoạt động SQL, bạn có thể tạo lược đồ của mình như (deluser, selectuser, updateuser) dưới dạng tên người dùng để dễ sử dụng.
Xem nguyên tắc đặc quyền tối thiểu .
Lọc dữ liệu: trước khi xây dựng bất kỳ đầu vào người dùng truy vấn nào, nó cần được xác nhận và lọc. Đối với lập trình viên, điều quan trọng là xác định một số thuộc tính cho từng biến đầu vào của người dùng:
kiểu dữ liệu, mẫu dữ liệu và độ dài dữ liệu . Trường có số nằm giữa (x và y) phải được xác thực chính xác bằng quy tắc chính xác và đối với trường là chuỗi (văn bản): mẫu là trường hợp, ví dụ: tên người dùng chỉ chứa một số ký tự, hãy để nói [a-zA-Z0-9_-.]. Độ dài khác nhau giữa (x và n) trong đó x và n (số nguyên, x <= n).
Quy tắc: tạo bộ lọc chính xác và quy tắc xác thực là những thực tiễn tốt nhất đối với tôi.
Sử dụng các công cụ khác: Ở đây, tôi cũng sẽ đồng ý với bạn rằng một câu lệnh đã được chuẩn bị (truy vấn tham số) và các thủ tục được lưu trữ. Nhược điểm ở đây là những cách này đòi hỏi những kỹ năng tiên tiến không tồn tại đối với hầu hết người dùng. Ý tưởng cơ bản ở đây là phân biệt giữa truy vấn SQL và dữ liệu được sử dụng bên trong. Cả hai cách tiếp cận có thể được sử dụng ngay cả với dữ liệu không an toàn, vì dữ liệu đầu vào của người dùng ở đây không thêm bất cứ điều gì vào truy vấn ban đầu, chẳng hạn như (bất kỳ hoặc x = x).
Để biết thêm thông tin, xin vui lòng đọc tờ Cheat phòng chống tiêm chích OWASP SQL .
Bây giờ, nếu bạn là người dùng nâng cao, hãy bắt đầu sử dụng biện pháp bảo vệ này theo ý muốn, nhưng, đối với người mới bắt đầu, nếu họ không thể nhanh chóng thực hiện quy trình được lưu trữ và chuẩn bị câu lệnh, tốt hơn hết là lọc dữ liệu đầu vào càng nhiều càng tốt.
Cuối cùng, hãy xem xét rằng người dùng gửi văn bản này bên dưới thay vì nhập tên người dùng của anh ấy / cô ấy:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
Đầu vào này có thể được kiểm tra sớm mà không cần bất kỳ tuyên bố chuẩn bị và quy trình được lưu trữ nào, nhưng để đảm bảo an toàn, sử dụng chúng bắt đầu sau khi lọc và xác thực dữ liệu người dùng.
Điểm cuối cùng là phát hiện hành vi bất ngờ đòi hỏi nhiều nỗ lực và phức tạp hơn; nó không được khuyến khích cho các ứng dụng web thông thường.
Hành vi bất ngờ trong đầu vào của người dùng ở trên là CHỌN, ĐOÀN, NẾU, ĐĂNG KÝ, BẾN, SHA và root. Một khi những từ này được phát hiện, bạn có thể tránh đầu vào.
CẬP NHẬT 1:
Một người dùng nhận xét rằng bài đăng này là vô ích, OK! Đây là những gì OWASP.ORG cung cấp :
Bảo vệ chính:
Lựa chọn # 1: Sử dụng câu lệnh chuẩn bị (tham số truy vấn)
Lựa chọn # 2: Sử dụng Stored Procedure
Lựa chọn # 3: Thoát tất cả các tài khoản Cung cấp Input
phòng thủ bổ sung:
Cũng Thực thi: Least Privilege
Cũng Thực hiện: White List Input Validation
Như bạn có thể biết, yêu cầu một bài viết nên được hỗ trợ bởi một đối số hợp lệ, ít nhất là bởi một tham chiếu! Mặt khác, nó được coi là một cuộc tấn công và một yêu sách tồi!
Cập nhật 2:
Từ hướng dẫn PHP, PHP: Báo cáo đã chuẩn bị - Hướng dẫn :
Thoát và SQL tiêm
Các biến giới hạn sẽ được thoát tự động bởi máy chủ. Máy chủ chèn các giá trị đã thoát của chúng tại các vị trí thích hợp vào mẫu câu lệnh trước khi thực hiện. Một gợi ý phải được cung cấp cho máy chủ về loại biến bị ràng buộc, để tạo ra một chuyển đổi phù hợp. Xem hàm mysqli_stmt_bind_param () để biết thêm thông tin.
Việc tự động thoát các giá trị trong máy chủ đôi khi được coi là một tính năng bảo mật để ngăn chặn việc tiêm SQL. Mức độ bảo mật tương tự có thể đạt được với các câu lệnh không được chuẩn bị nếu các giá trị đầu vào được thoát chính xác.
Cập nhật 3:
Tôi đã tạo các trường hợp thử nghiệm để biết cách PDO và MySQLi gửi truy vấn đến máy chủ MySQL khi sử dụng câu lệnh đã chuẩn bị:
PDO:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
Nhật ký truy vấn:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
Nhật ký truy vấn:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
Rõ ràng là một tuyên bố đã chuẩn bị cũng đang thoát khỏi dữ liệu, không có gì khác.
Như đã đề cập trong tuyên bố trên,
Việc tự động thoát các giá trị trong máy chủ đôi khi được coi là một tính năng bảo mật để ngăn chặn việc tiêm SQL. Mức độ bảo mật tương tự có thể đạt được với các câu lệnh không được chuẩn bị, nếu các giá trị đầu vào được thoát chính xác
Do đó, điều này chứng tỏ rằng xác thực dữ liệu như intval()
là một ý tưởng tốt cho các giá trị số nguyên trước khi gửi bất kỳ truy vấn nào. Ngoài ra, ngăn chặn dữ liệu người dùng độc hại trước khi gửi truy vấn là một cách tiếp cận chính xác và hợp lệ .
Vui lòng xem câu hỏi này để biết thêm chi tiết: PDO gửi truy vấn thô tới MySQL trong khi Mysqli gửi truy vấn đã chuẩn bị, cả hai đều tạo ra kết quả giống nhau
Người giới thiệu:
- Bảng cheat SQL
- Tiêm SQL
- Bảo mật thông tin
- Nguyên tắc bảo mật
- Xác nhận dữ liệu