Các tuyên bố chuẩn bị PDO có đủ để ngăn chặn SQL tiêm không?


661

Hãy nói rằng tôi có mã như thế này:

$dbh = new PDO("blahblah");

$stmt = $dbh->prepare('SELECT * FROM users where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

Tài liệu PDO nói:

Các tham số cho các báo cáo được chuẩn bị không cần phải được trích dẫn; Trình điều khiển xử lý nó cho bạn.

Đó có thực sự là tất cả những gì tôi cần làm để tránh tiêm SQL không? Nó thực sự dễ dàng?

Bạn có thể giả định MySQL nếu nó làm cho một sự khác biệt. Ngoài ra, tôi thực sự chỉ tò mò về việc sử dụng các câu lệnh được chuẩn bị để chống lại việc tiêm SQL. Trong bối cảnh này, tôi không quan tâm đến XSS hoặc các lỗ hổng có thể khác.


5
cách tiếp cận tốt hơn câu trả lời số 7 stackoverflow.com/questions/134099/
triệt

Câu trả lời:


806

Câu trả lời ngắn gọn là KHÔNG , PDO chuẩn bị sẽ không bảo vệ bạn khỏi tất cả các cuộc tấn công SQL-Injection có thể. Đối với các trường hợp cạnh tối nghĩa nhất định.

Tôi đang điều chỉnh câu trả lời này để nói về PDO ...

Câu trả lời dài không quá dễ. Nó dựa trên một cuộc tấn công được chứng minh ở đây .

Cuộc tấn công

Vì vậy, hãy bắt đầu bằng cách hiển thị cuộc tấn công ...

$pdo->query('SET NAMES gbk');
$var = "\xbf\x27 OR 1=1 /*";
$query = 'SELECT * FROM test WHERE name = ? LIMIT 1';
$stmt = $pdo->prepare($query);
$stmt->execute(array($var));

Trong một số trường hợp nhất định, điều đó sẽ trả về hơn 1 hàng. Hãy phân tích những gì đang diễn ra ở đây:

  1. Chọn một bộ ký tự

    $pdo->query('SET NAMES gbk');

    Để cuộc tấn công này hoạt động, chúng ta cần mã hóa mà máy chủ mong đợi trên cả kết nối để mã hóa 'như trong ASCII tức là 0x27 để có một số ký tự có byte cuối cùng là ASCII \tức là 0x5c. Khi nó quay ra, có 5 mã hóa như hỗ trợ trong MySQL 5.6 theo mặc định: big5, cp932, gb2312, gbksjis. Chúng tôi sẽ chọn gbkở đây.

    Bây giờ, rất quan trọng để lưu ý việc sử dụng SET NAMESở đây. Cái này đặt bộ ký tự TRÊN MÁY CHỦ . Có một cách khác để làm điều đó, nhưng chúng ta sẽ đến đó sớm thôi.

  2. Tải trọng

    Tải trọng mà chúng ta sẽ sử dụng cho phép tiêm này bắt đầu bằng chuỗi byte 0xbf27. Trong gbkđó, đó là một nhân vật đa bào không hợp lệ; trong latin1, đó là chuỗi ¿'. Lưu ý rằng trong latin1 gbk , 0x27trên chính nó là một 'nhân vật theo nghĩa đen .

    Chúng tôi đã chọn tải trọng này bởi vì, nếu chúng tôi gọi addslashes()nó, chúng tôi sẽ chèn ASCII \tức là 0x5ctrước 'ký tự. Vì vậy, chúng tôi sẽ kết thúc 0xbf5c27, trong đó gbklà một chuỗi hai ký tự: 0xbf5ctheo sau 0x27. Hay nói cách khác, một nhân vật hợp lệ theo sau là một người không được giải thoát '. Nhưng chúng tôi không sử dụng addslashes(). Vì vậy, bước tiếp theo ...

  3. $ stmt-> thực thi ()

    Điều quan trọng cần nhận ra ở đây là PDO theo mặc định KHÔNG thực hiện các tuyên bố chuẩn bị thực sự. Nó mô phỏng chúng (đối với MySQL). Do đó, PDO bên trong xây dựng chuỗi truy vấn, gọi mysql_real_escape_string()(hàm API C của MySQL) trên mỗi giá trị chuỗi bị ràng buộc.

    Lệnh gọi API C mysql_real_escape_string()khác với addslashes()ở chỗ nó biết bộ ký tự kết nối. Vì vậy, nó có thể thực hiện thoát đúng cho bộ ký tự mà máy chủ đang mong đợi. Tuy nhiên, cho đến thời điểm này, khách hàng nghĩ rằng chúng tôi vẫn đang sử dụng latin1cho kết nối, bởi vì chúng tôi không bao giờ nói với nó khác. Chúng tôi đã nói với máy chủ chúng tôi đang sử dụng gbk, nhưng khách hàng vẫn nghĩ rằng nó latin1.

    Do đó, lệnh gọi mysql_real_escape_string()chèn dấu gạch chéo ngược và chúng tôi có một 'ký tự treo miễn phí trong nội dung "thoát" của chúng tôi! Thực tế, nếu chúng ta nhìn vào $varbộ gbkký tự, chúng ta sẽ thấy:

    縗 'HOẶC 1 = 1 / *

    Đó chính xác là những gì cuộc tấn công yêu cầu.

  4. Truy vấn

    Phần này chỉ là một hình thức, nhưng đây là truy vấn được kết xuất:

    SELECT * FROM test WHERE name = '縗' OR 1=1 /*' LIMIT 1

Xin chúc mừng, bạn vừa tấn công thành công một chương trình sử dụng Tuyên bố chuẩn bị PDO ...

Cách khắc phục đơn giản

Bây giờ, đáng chú ý là bạn có thể ngăn chặn điều này bằng cách vô hiệu hóa các câu lệnh được chuẩn bị mô phỏng:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Điều này thường sẽ dẫn đến một tuyên bố được chuẩn bị thực sự (tức là dữ liệu được gửi trong một gói riêng biệt từ truy vấn). Tuy nhiên, lưu ý rằng PDO sẽ âm thầm dự phòng các giả lập mà MySQL không thể chuẩn bị một cách tự nhiên: những thứ mà nó có thể được liệt kê trong hướng dẫn, nhưng hãy cẩn thận để chọn phiên bản máy chủ phù hợp).

Sửa lỗi chính xác

Vấn đề ở đây là chúng tôi đã không gọi API C mysql_set_charset()thay vì SET NAMES. Nếu chúng tôi làm như vậy, chúng tôi sẽ ổn nếu chúng tôi sử dụng bản phát hành MySQL từ năm 2006.

Nếu bạn đang sử dụng một phiên bản MySQL trước, sau đó là một lỗi trong mysql_real_escape_string()có nghĩa là ký tự nhiều byte không hợp lệ như những người trong Payload của chúng tôi bị đối xử như byte duy nhất cho mục đích thoát ngay cả khi khách hàng đã được thông báo một cách chính xác của mã hóa kết nối và do đó cuộc tấn công này sẽ vẫn thành công Lỗi này đã được cố định trong MySQL 4.1.20 , 5.0.225.1.11 .

Nhưng điều tồi tệ nhất là PDOđã không để lộ API C cho mysql_set_charset()đến ngày 5.3.6, vì vậy trong các phiên bản trước, nó không thể ngăn chặn cuộc tấn công này cho mọi lệnh có thể! Bây giờ nó được hiển thị dưới dạng tham số DSN , nên được sử dụng thay vì SET NAMES ...

Ân điển cứu rỗi

Như chúng ta đã nói ngay từ đầu, để cuộc tấn công này hoạt động, kết nối cơ sở dữ liệu phải được mã hóa bằng bộ ký tự dễ bị tổn thương. utf8mb4không dễ bị tổn thương và chưa thể hỗ trợ tất cả các ký tự Unicode: vì vậy bạn có thể chọn để sử dụng mà thay vào đó, nhưng nó đã chỉ được đưa ra từ MySQL 5.5.3. Một cách khác là utf8, nó cũng không dễ bị tổn thương và có thể hỗ trợ toàn bộ Mặt phẳng đa ngôn ngữ Unicode Basic .

Ngoài ra, bạn có thể kích hoạt NO_BACKSLASH_ESCAPESchế độ SQL, trong đó (trong số những thứ khác) làm thay đổi hoạt động của mysql_real_escape_string(). Khi bật chế độ này, 0x27sẽ được thay thế bằng 0x2727thay vì 0x5c27và do đó, quá trình thoát không thể tạo các ký tự hợp lệ trong bất kỳ mã hóa dễ bị tổn thương nào mà chúng không tồn tại trước đó (nghĩa 0xbf27là vẫn 0xbf27v.v.) - vì vậy máy chủ vẫn sẽ từ chối chuỗi là không hợp lệ . Tuy nhiên, hãy xem câu trả lời của @ eggyal để biết một lỗ hổng khác có thể phát sinh từ việc sử dụng chế độ SQL này (mặc dù không phải với PDO).

Ví dụ an toàn

Các ví dụ sau đây là an toàn:

mysql_query('SET NAMES utf8');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

Bởi vì máy chủ đang mong đợi utf8...

mysql_set_charset('gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

Bởi vì chúng tôi đã đặt đúng bộ ký tự sao cho máy khách và máy chủ khớp.

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES gbk');
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

Bởi vì chúng tôi đã tắt các tuyên bố chuẩn bị mô phỏng.

$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk', $user, $password);
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

Bởi vì chúng tôi đã thiết lập đúng ký tự.

$mysqli->query('SET NAMES gbk');
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "\xbf\x27 OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();

Bởi vì MySQLi luôn luôn chuẩn bị các tuyên bố chuẩn bị.

Kết thúc

Nếu bạn:

  • Sử dụng các phiên bản hiện đại của MySQL (cuối 5.1, tất cả 5.5, 5.6, v.v.) tham số bộ ký tự DSN của PDO (trong PHP ≥ 5.3.6)

HOẶC LÀ

  • Không sử dụng bộ ký tự dễ bị tổn thương để mã hóa kết nối (bạn chỉ sử dụng utf8/ latin1/ ascii/ etc)

HOẶC LÀ

  • Kích hoạt NO_BACKSLASH_ESCAPESchế độ SQL

Bạn an toàn 100%.

Mặt khác, bạn dễ bị tổn thương ngay cả khi bạn đang sử dụng Tuyên bố chuẩn bị PDO ...

Phụ lục

Tôi đã dần dần làm việc trên một bản vá để thay đổi mặc định để không giả lập chuẩn bị cho phiên bản PHP trong tương lai. Vấn đề mà tôi gặp phải là rất nhiều bài kiểm tra bị hỏng khi tôi làm điều đó. Một vấn đề là các chế phẩm được mô phỏng sẽ chỉ ném lỗi cú pháp khi thực thi, nhưng các chuẩn bị thực sự sẽ ném lỗi khi chuẩn bị. Vì vậy, điều đó có thể gây ra vấn đề (và là một phần của các bài kiểm tra lý do đang làm hỏng).


47
Đây là câu trả lời tốt nhất mà tôi tìm thấy .. bạn có thể cung cấp một liên kết để tham khảo thêm không?
Tĩnh

1
@nicogawenda: đó là một lỗi khác. Trước 5.0.22, mysql_real_escape_stringsẽ không xử lý đúng các trường hợp kết nối được đặt đúng thành BIG5 / GBK. Vì vậy, thực sự ngay cả việc gọi mysql_set_charset()mys mys <5.0.22 cũng sẽ dễ bị lỗi này! Vì vậy, không, bài đăng này vẫn có thể áp dụng cho 5.0.22 (vì mysql_real_escape_opes chỉ dành cho các cuộc gọi từ mysql_set_charset()đó, đó là những gì bài đăng này đang nói về việc bỏ qua) ...
ircmaxell

1
@progfa Cho dù có hay không, bạn nên luôn xác thực đầu vào của mình trên máy chủ trước khi làm bất cứ điều gì với dữ liệu người dùng.
Tek

2
Xin lưu ý rằng NO_BACKSLASH_ESCAPEScũng có thể giới thiệu các lỗ hổng mới: stackoverflow.com/a/23277864/1014813
lepix

2
@slevin "HOẶC 1 = 1" là một trình giữ chỗ cho bất cứ điều gì bạn muốn. Đúng, đó là tìm kiếm một giá trị trong tên, nhưng hãy tưởng tượng phần "HOẶC 1 = 1" là "UNION CHỌN * TỪ người dùng". Bây giờ bạn kiểm soát truy vấn và như vậy có thể lạm dụng nó ...
ircmaxell

515

Các câu lệnh được chuẩn bị / các truy vấn được tham số hóa thường đủ để ngăn chặn lệnh tiêm thứ 1 trên câu lệnh đó * . Nếu bạn sử dụng sql động chưa được kiểm tra ở bất kỳ nơi nào khác trong ứng dụng của bạn, bạn vẫn dễ bị tiêm thứ 2 .

Việc tiêm thứ tự 2 có nghĩa là dữ liệu đã được chuyển qua cơ sở dữ liệu một lần trước khi được đưa vào truy vấn và khó khăn hơn nhiều. AFAIK, bạn hầu như không bao giờ thấy các cuộc tấn công thứ 2 được thiết kế thực sự, vì những kẻ tấn công thường dễ dàng hơn trong kỹ thuật xã hội, nhưng đôi khi bạn gặp lỗi thứ 2 do các 'nhân vật lành tính hơn hoặc tương tự.

Bạn có thể thực hiện một cuộc tấn công tiêm thứ tự thứ 2 khi bạn có thể khiến một giá trị được lưu trữ trong cơ sở dữ liệu mà sau này được sử dụng như một nghĩa đen trong truy vấn. Ví dụ: giả sử bạn nhập thông tin sau đây làm tên người dùng mới khi tạo tài khoản trên trang web (giả sử MySQL DB cho câu hỏi này):

' + (SELECT UserName + '_' + Password FROM Users LIMIT 1) + '

Nếu không có hạn chế nào khác đối với tên người dùng, một câu lệnh được chuẩn bị vẫn sẽ đảm bảo rằng truy vấn được nhúng ở trên không thực thi tại thời điểm chèn và lưu trữ giá trị chính xác trong cơ sở dữ liệu. Tuy nhiên, hãy tưởng tượng rằng sau đó ứng dụng lấy tên người dùng của bạn từ cơ sở dữ liệu và sử dụng nối chuỗi để đưa giá trị đó vào một truy vấn mới. Bạn có thể thấy mật khẩu của người khác. Vì một vài tên đầu tiên trong bảng người dùng có xu hướng là quản trị viên, bạn cũng có thể đã cho đi trang trại. (Cũng lưu ý: đây là một lý do nữa để không lưu trữ mật khẩu ở dạng văn bản đơn giản!)

Sau đó, chúng ta thấy rằng các câu lệnh được chuẩn bị là đủ cho một truy vấn, nhưng bản thân chúng không đủ để bảo vệ chống lại các cuộc tấn công tiêm sql trong toàn bộ ứng dụng, vì chúng thiếu một cơ chế để thực thi tất cả quyền truy cập vào cơ sở dữ liệu trong một ứng dụng sử dụng an toàn mã. Tuy nhiên, được sử dụng như một phần của thiết kế ứng dụng tốt - có thể bao gồm các thực tiễn như xem lại mã hoặc phân tích tĩnh hoặc sử dụng ORM, lớp dữ liệu hoặc lớp dịch vụ giới hạn các câu lệnh được chuẩn bị sql động công cụ chính để giải quyết Sql Injection vấn đề.Nếu bạn tuân theo các nguyên tắc thiết kế ứng dụng tốt, sao cho việc truy cập dữ liệu của bạn được tách biệt với phần còn lại của chương trình, việc thực thi hoặc kiểm toán rằng mọi truy vấn đều sử dụng tham số chính xác. Trong trường hợp này, tiêm sql (cả thứ tự đầu tiên và thứ hai) hoàn toàn bị ngăn chặn.


* Hóa ra MySql / PHP (ổn, đã) chỉ câm lặng về việc xử lý các tham số khi có các ký tự rộng, và vẫn có một trường hợp hiếm hoi được nêu trong câu trả lời được bình chọn cao khác ở đây có thể cho phép tiêm qua một tham số truy vấn.


6
Nó thật thú vị. Tôi đã không nhận thức được thứ tự 1 so với thứ tự 2. Bạn có thể giải thích thêm một chút về cách thức hoạt động của đơn hàng thứ 2 không?
Đánh dấu Biek

193
Nếu TẤT CẢ các truy vấn của bạn được tham số hóa, bạn cũng được bảo vệ chống lại lệnh tiêm thứ 2. Tiêm thứ tự 1 là quên rằng dữ liệu người dùng là không đáng tin cậy. Việc tiêm lệnh thứ 2 đang quên rằng dữ liệu cơ sở dữ liệu là không đáng tin cậy (vì nó xuất phát từ người dùng ban đầu).
cjm

6
Cảm ơn cjm. Tôi cũng thấy bài viết này hữu ích trong việc giải thích các mũi tiêm thứ 2: codeproject.com/KB/database/SqlInjectionAttacks.aspx
Mark Biek

49
À, vâng. Nhưng những gì về tiêm thứ ba . Phải nhận thức được những điều đó.
troelskn

81
@troelskn phải là nơi nhà phát triển là nguồn dữ liệu không đáng tin cậy
MikeMurko

45

Không, không phải lúc nào họ cũng vậy.

Nó phụ thuộc vào việc bạn có cho phép đầu vào của người dùng được đặt trong chính truy vấn hay không. Ví dụ:

$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];

$stmt = $dbh->prepare('SELECT * FROM ' . $tableToUse . ' where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

sẽ dễ bị tấn công SQL và sử dụng các câu lệnh được chuẩn bị trong ví dụ này sẽ không hoạt động, bởi vì đầu vào của người dùng được sử dụng làm định danh, không phải là dữ liệu. Câu trả lời đúng ở đây sẽ là sử dụng một số loại lọc / xác thực như:

$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];
$allowedTables = array('users','admins','moderators');
if (!in_array($tableToUse,$allowedTables))    
 $tableToUse = 'users';

$stmt = $dbh->prepare('SELECT * FROM ' . $tableToUse . ' where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

Lưu ý: bạn không thể sử dụng PDO để liên kết dữ liệu bên ngoài DDL (Ngôn ngữ định nghĩa dữ liệu), nghĩa là điều này không hoạt động:

$stmt = $dbh->prepare('SELECT * FROM foo ORDER BY :userSuppliedData');

Lý do tại sao ở trên không hoạt động là vì DESCASCkhông phải là dữ liệu . PDO chỉ có thể thoát dữ liệu . Thứ hai, bạn thậm chí không thể đặt 'dấu ngoặc kép xung quanh nó. Cách duy nhất để cho phép người dùng chọn sắp xếp là lọc thủ công và kiểm tra xem đó có phải DESChay không ASC.


11
Tôi có thiếu điều gì ở đây không nhưng toàn bộ quan điểm đã chuẩn bị để tránh đối xử với sql như một chuỗi? Sẽ không có cái gì đó như $ dbh-> chuẩn bị ('CHỌN * TỪ: bảngToUse nơi tên người dùng =: tên người dùng'); giải quyết vấn đề của bạn?
Rob Forrest

4
@RobForrest có bạn đang thiếu :). Dữ liệu bạn liên kết chỉ hoạt động cho DDL (Ngôn ngữ định nghĩa dữ liệu). Bạn cần những trích dẫn và thoát thích hợp. Đặt dấu ngoặc kép cho các phần khác của truy vấn sẽ phá vỡ nó với xác suất cao. Ví dụ, SELECT * FROM 'table'có thể sai vì nó nên SELECT * FROM `table`hoặc không có bất kỳ backsticks. Sau đó, một số thứ như ORDER BY DESCnơi DESCxuất phát từ người dùng không thể chỉ đơn giản là bỏ trốn. Vì vậy, các kịch bản thực tế là không giới hạn.
Tháp

8
Tôi tự hỏi làm thế nào 6 người có thể đưa ra một nhận xét đề xuất việc sử dụng sai một tuyên bố đã chuẩn bị. Thậm chí họ đã thử nó một lần, họ đã phát hiện ra rằng việc sử dụng tham số được đặt tên thay cho tên bảng sẽ không hoạt động.
Félix Gagnon-Grenier

Đây là một hướng dẫn tuyệt vời về PDO nếu bạn muốn tìm hiểu nó. a2znotes.blogspot.in/2014/09/int sinhtion
RN Kushwaha

11
Bạn không bao giờ nên sử dụng chuỗi truy vấn / phần thân POST để chọn bảng để sử dụng. Nếu bạn không có mô hình, ít nhất hãy sử dụng a switchđể lấy tên bảng.
ZiggyTheroulette

29

Vâng, nó là đủ. Cách thức các cuộc tấn công kiểu tiêm hoạt động, bằng cách nào đó có được một trình thông dịch (Cơ sở dữ liệu) để đánh giá một cái gì đó, đáng lẽ phải là dữ liệu, như thể đó là mã. Điều này chỉ có thể nếu bạn trộn mã và dữ liệu trong cùng một phương tiện (Ví dụ: khi bạn xây dựng một truy vấn dưới dạng chuỗi).

Các truy vấn được tham số hóa hoạt động bằng cách gửi mã và dữ liệu riêng biệt, vì vậy sẽ không bao giờ có thể tìm thấy lỗ hổng trong đó.

Bạn vẫn có thể dễ bị tổn thương trước các cuộc tấn công kiểu tiêm khác. Ví dụ: nếu bạn sử dụng dữ liệu trong trang HTML, bạn có thể phải chịu các cuộc tấn công kiểu XSS.


10
"Không bao giờ" là cách cường điệu hóa nó, đến mức gây hiểu lầm. Nếu bạn đang sử dụng các câu lệnh được chuẩn bị không chính xác, sẽ không tốt hơn nhiều so với việc không sử dụng chúng. (Tất nhiên, một "tuyên bố đã chuẩn bị" có đầu vào của người dùng được đưa vào để đánh bại mục đích ... nhưng tôi thực sự đã thấy nó được thực hiện. Và các câu lệnh được chuẩn bị không thể xử lý các định danh (tên bảng, v.v.) làm tham số.) Thêm do đó, một số trình điều khiển PDO mô phỏng các câu lệnh đã được chuẩn bị và có chỗ cho chúng thực hiện không chính xác (ví dụ: bằng cách phân tích cú pháp một nửa khẳng định SQL). Phiên bản ngắn: không bao giờ cho rằng nó dễ dàng.
cHao

29

Không, điều này là không đủ (trong một số trường hợp cụ thể)! Theo mặc định, PDO sử dụng các câu lệnh được chuẩn bị mô phỏng khi sử dụng MySQL làm trình điều khiển cơ sở dữ liệu. Bạn phải luôn luôn vô hiệu hóa các câu lệnh được chuẩn bị mô phỏng khi sử dụng MySQL và PDO:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Một điều nữa luôn luôn phải được thực hiện, nó thiết lập mã hóa chính xác của cơ sở dữ liệu:

$dbh = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

Cũng xem câu hỏi liên quan này: Làm cách nào tôi có thể ngăn SQL tiêm trong PHP?

Cũng lưu ý rằng đó chỉ là về phía cơ sở dữ liệu của những thứ bạn vẫn sẽ phải tự xem khi hiển thị dữ liệu. Ví dụ: bằng cách sử dụng htmlspecialchars()lại với kiểu mã hóa và trích dẫn chính xác.


14

Cá nhân tôi luôn luôn chạy một số hình thức vệ sinh trên dữ liệu trước tiên vì bạn không bao giờ có thể tin tưởng đầu vào của người dùng, tuy nhiên khi sử dụng trình giữ chỗ / tham số ràng buộc dữ liệu được nhập vào máy chủ vào câu lệnh sql và sau đó liên kết với nhau. Chìa khóa ở đây là điều này liên kết dữ liệu được cung cấp với một loại cụ thể và cách sử dụng cụ thể và loại bỏ mọi cơ hội để thay đổi logic của câu lệnh SQL.


1

Eaven nếu bạn định ngăn chặn front-end tiêm sql, sử dụng kiểm tra html hoặc js, bạn phải xem xét rằng kiểm tra front-end là "có thể bỏ qua".

Bạn có thể vô hiệu hóa js hoặc chỉnh sửa một mẫu bằng công cụ phát triển front-end (được tích hợp sẵn với firefox hoặc chrome).

Vì vậy, để ngăn chặn việc tiêm SQL, sẽ được quyền vệ sinh phụ trợ ngày đầu vào bên trong bộ điều khiển của bạn.

Tôi muốn đề nghị với bạn sử dụng hàm PHP gốc của bộ lọc filter_input () để vệ sinh các giá trị GET và INPUT.

Nếu bạn muốn tiếp tục bảo mật, đối với các truy vấn cơ sở dữ liệu hợp lý, tôi muốn đề xuất với bạn sử dụng biểu thức chính quy để xác thực định dạng dữ liệu. preg_match () sẽ giúp bạn trong trường hợp này! Nhưng hãy cẩn thận! Động cơ Regex không quá nhẹ. Chỉ sử dụng nó nếu cần thiết, nếu không hiệu suất ứng dụng của bạn sẽ giảm.

Bảo mật có chi phí, nhưng đừng lãng phí hiệu suất của bạn!

Ví dụ dễ dàng:

nếu bạn muốn kiểm tra lại nếu một giá trị, nhận được từ GET là một số, nhỏ hơn 99 nếu (! preg_match ('/ [0-9] {1,2} /')) {...} nặng hơn

if (isset($value) && intval($value)) <99) {...}

Vì vậy, câu trả lời cuối cùng là: "Không! Tuyên bố chuẩn bị PDO không ngăn chặn tất cả các loại tiêm sql"; Nó không ngăn chặn các giá trị bất ngờ, chỉ là sự kết hợp bất ngờ


5
Bạn đang nhầm lẫn việc tiêm SQL với một thứ khác khiến câu trả lời của bạn hoàn toàn không liên quan
Ý thức chung của bạn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.