Thay thế cho mysql_real_escape_string mà không cần kết nối với DB


91

Tôi muốn có một hàm hoạt động dưới dạng mysql_real_escape_string mà không cần kết nối với cơ sở dữ liệu vì đôi khi tôi cần thực hiện thử nghiệm khô mà không có kết nối DB. mysql_escape_string không được dùng nữa và do đó không mong muốn. Một số phát hiện của tôi:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064



1
+1 Tôi đang tự viết lớp MySQL và sử dụng mysql_real_escape_string () cho mục đích ràng buộc tham số. Tôi tránh sử dụng mysqli vì không phải tất cả các hosting đều hỗ trợ nó. Tôi cũng tránh thư viện nhiều tệp & nhiều lớp. Những gì tôi cần chỉ là một Class đơn gọn gàng và sạch sẽ. Cảm ơn bạn!
Việt

+1 cho tôi nữa. Trường hợp sử dụng của tôi là một APi SugarCRM, nơi tôi cần đẩy các đoạn SQL đến phiên bản SugarCRM từ xa thông qua API. Tuy nhiên, điều đó thật khó chịu, đó là những gì tôi phải làm việc (đi gõ một số nhà phát triển SugarCRM với nhau). Tôi cần thoát các chuỗi trong SQL trong ứng dụng sử dụng API và nó hoàn toàn tách biệt với cơ sở dữ liệu đằng sau phiên bản SugarCRM.
Jason

Câu trả lời:


75

Không thể thoát một chuỗi một cách an toàn mà không có kết nối DB. mysql_real_escape_string()và các câu lệnh đã chuẩn bị cần kết nối với cơ sở dữ liệu để chúng có thể thoát khỏi chuỗi bằng cách sử dụng bộ ký tự thích hợp - nếu không, các cuộc tấn công SQL injection vẫn có thể xảy ra bằng cách sử dụng các ký tự nhiều byte.

Nếu bạn chỉ đang thử nghiệm , thì bạn cũng có thể sử dụng mysql_escape_string(), nó không được đảm bảo 100% chống lại các cuộc tấn công SQL injection, nhưng không thể xây dựng bất cứ thứ gì an toàn hơn mà không có kết nối DB.


1
+1 Cảm ơn bạn đã lưu ý. Tôi không chắc chắn về cách kiểm tra chống lại các cuộc tấn công SQL injection bằng cách sử dụng các ký tự nhiều byte.
Việt

2
Tôi đã được cung cấp một số mã cũ để cập nhật. Nó sử dụng mysql_escape_stringmà không có kết nối (vẫn đang cố gắng tìm ra lý do tại sao). Vì chức năng đó không được dùng nữa nên tôi chỉ tự hỏi làm cách nào để thay thế nó. Chắc chắn có vẻ hợp lý khi người ta có thể chỉ định "bộ ký tự thích hợp" trong bất kỳ hàm nào thay thế nó mà không cần mở kết nối.
JohnK

3
Không thể nào? Mysql_real_escape_string nhận được gì từ kết nối cơ sở dữ liệu không phải là dữ liệu cấu hình có thể được chuyển bằng tay tới một hàm tương đương? Chỉnh sửa: chỉ cần đọc bên dưới, nó gọi hàm thư viện trong MySQL, vì vậy có một số xử lý xảy ra bên ngoài PHP. Nó có thể vẫn có thể di động được, nhưng việc cập nhật nó sẽ là một dự án.
Jason

2
Điều gì sẽ xảy ra nếu bộ ký tự DB được biết trước?
jchook

7
Vâng nếu bạn biết bộ ký tự, điều gì ngăn cản việc thoát ra mà không có kết nối?
Johan

66

Vâng, theo trang tham chiếu hàm mysql_real_escape_string : "mysql_real_escape_string () gọi hàm thư viện của MySQL là mysql_real_escape_string, hàm này thoát khỏi các ký tự sau: \ x00, \ n, \ r, \, '," và \ x1a. "

Với ý nghĩ đó, thì chức năng được cung cấp trong liên kết thứ hai mà bạn đã đăng sẽ thực hiện chính xác những gì bạn cần:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}

6
Cảm ơn. Tôi muốn đề xuất một cái gì đó khác: function Escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Việt

1
tại sao \ x1a được thay thế bằng \\\ x1a thay vì \\ x1a? Đây có phải là lỗi đánh máy không?
Michael Z

16
-1 Điều này cực kỳ nguy hiểm. Nếu kết nối cơ sở dữ liệu đang sử dụng bộ ký tự nhiều byte, các thay thế theo từng byte đơn giản như thế này có thể dẫn đến hỏng dữ liệu (bao gồm các ký tự thoát / trích dẫn) - điều này có thể bị kẻ tấn công độc hại cố tình khai thác để chèn SQL tùy ý.
eggyal

Nếu bạn đặt sai ký tự vào điều này, nó có thể nguy hiểm. Đối với các bộ ký tự nhiều byte, nếu mysql đang sử dụng thì ai đó có thể chỉ cần đưa vào một byte để hủy bỏ \\. Các bộ ký tự multiebyte thường có thể lấy bất kỳ thứ gì dưới dạng byte thứ hai bao gồm \\ cho mysql sẽ không xem nó là một \\ độc lập mà là một phần của ký tự multibyte. Tôi không biết điều gì xảy ra với UTF8. Tôi hy vọng rằng với [0xB0, '\\'] điều đó xảy ra khi nhấn một byte không hợp lệ \\ chỉ dừng lại và bắt đầu lại với byte đó thay vì nuốt nó.
jgmjgm

1
Nếu tôi biết rằng bộ ký tự là utf8, liệu có an toàn để sử dụng mb_strpos()(và mb_substr()tạo hành vi tương tự như substr_replace()) để thực hiện việc này không?
SOFe

28

Đối lập trực tiếp với câu trả lời khác của tôi, hàm sau đây có thể an toàn, ngay cả với các ký tự nhiều byte.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

Tôi hy vọng ai đó hiểu biết hơn bản thân tôi có thể cho tôi biết tại sao đoạn mã trên không hoạt động ...


+1 Cảm ơn vì đã nỗ lực thêm. Tôi sẽ đi vòng quanh để tìm hiểu thêm về việc tiêm SQL liên quan đến nhiều byte.
Việt

Tôi đoán nó phải là $ return. = '\ X'. dechex ($ ord); thay vào đó
Việt

1
Theo nguyên tắc chung, tôi thích sử dụng '\\' ngay cả trong các chuỗi được trích dẫn đơn, chỉ vì một '\' duy nhất có thể ảnh hưởng đến ký tự tiếp theo nếu bạn không cẩn thận. Tôi có lẽ chỉ là OCD một lần nữa.
quá nhiều php

1
Hàm này không tuân theo các quy tắc thoát mysql và sẽ dẫn đến mất tính toàn vẹn của dữ liệu. "MySQL nhận dạng các chuỗi thoát được hiển thị trong Bảng 9.1," Chuỗi thoát ký tự đặc biệt ". Đối với tất cả các chuỗi thoát khác, dấu gạch chéo ngược bị bỏ qua. Nghĩa là, ký tự thoát được hiểu như thể nó không được thoát. Ví dụ:“ \ x ” chỉ là “x”. " - dev.mysql.com/doc/refman/5.6/en/…
khóa dán

2
\ XAA có thực sự có nghĩa gì khác ngoài văn bản "xAA" trong một chuỗi MySQL theo nghĩa đen không? Tài liệu có vẻ nói rằng \ x không có bất kỳ ý nghĩa đặc biệt nào, vì vậy \ sẽ bị bỏ qua. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason

6

Từ nghiên cứu sâu hơn, tôi đã tìm thấy:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

Khắc phục bảo mật:

Một lỗ hổng bảo mật SQL-injection đã được tìm thấy trong quá trình xử lý mã hóa nhiều byte. Lỗi nằm trong máy chủ, phân tích cú pháp sai chuỗi được thoát bằng hàm API mysql_real_escape_string () C API.

Lỗ hổng này được phát hiện và báo cáo bởi Josh Berkus và Tom Lane như một phần của sự hợp tác bảo mật liên dự án của tập đoàn OSDB. Để biết thêm thông tin về SQL injection, vui lòng xem văn bản sau.

Thảo luận. Một lỗ hổng bảo mật của SQL injection đã được tìm thấy trong quá trình xử lý mã hóa nhiều byte. Lỗ hổng bảo mật chèn SQL có thể bao gồm một tình huống trong đó khi người dùng cung cấp dữ liệu để chèn vào cơ sở dữ liệu, người dùng có thể đưa câu lệnh SQL vào dữ liệu mà máy chủ sẽ thực thi. Liên quan đến lỗ hổng này, khi sử dụng tính năng thoát không nhận biết bộ ký tự (ví dụ: addlash () trong PHP), có thể bỏ qua việc thoát trong một số bộ ký tự nhiều byte (ví dụ: SJIS, BIG5 và GBK). Do đó, một hàm như addlash () không thể ngăn chặn các cuộc tấn công SQL-injection. Không thể sửa lỗi này ở phía máy chủ. Giải pháp tốt nhất là các ứng dụng sử dụng tính năng thoát nhận biết bộ ký tự được cung cấp bởi một hàm như mysql_real_escape_string ().

Tuy nhiên, một lỗi đã được phát hiện trong cách máy chủ MySQL phân tích cú pháp đầu ra của mysql_real_escape_string (). Kết quả là, ngay cả khi hàm nhận biết bộ ký tự mysql_real_escape_string () được sử dụng, vẫn có thể đưa vào SQL. Lỗi này đã được cố định.

Cách giải quyết. Nếu bạn không thể nâng cấp MySQL lên phiên bản bao gồm bản sửa lỗi trong phân tích cú pháp mysql_real_escape_string (), nhưng chạy MySQL 5.0.1 trở lên, bạn có thể sử dụng chế độ SQL NO_BACKSLASH_ESCAPES như một giải pháp thay thế. (Chế độ này đã được giới thiệu trong MySQL 5.0.1.) NO_BACKSLASH_ESCAPES cho phép chế độ tương thích chuẩn SQL, trong đó dấu gạch chéo ngược không được coi là một ký tự đặc biệt. Kết quả là các truy vấn sẽ không thành công.

Để đặt chế độ này cho kết nối hiện tại, hãy nhập câu lệnh SQL sau:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Bạn cũng có thể đặt chế độ trên toàn cầu cho tất cả các máy khách:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Chế độ SQL này cũng có thể được bật tự động khi máy chủ khởi động bằng cách sử dụng tùy chọn dòng lệnh --sql-mode = NO_BACKSLASH_ESCAPES hoặc bằng cách đặt sql-mode = NO_BACKSLASH_ESCAPES trong tệp tùy chọn máy chủ (ví dụ: my.cnf hoặc my.ini , tùy thuộc vào hệ thống của bạn). (Lỗi # 8378, CVE-2006-2753)

Xem thêm Lỗi # 8303.


1
Điều này đã được sửa từ lâu.
Common Sense của bạn

2
Ngoài ra, hãy cẩn thận khi NO_BACKSLASH_ESCAPES giới thiệu các lỗ hổng khác .
eggyal

2
Đã sửa lỗi trong 5.1.11 - Liên kết bị hỏng, đây là kho lưu trữ: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion
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.