2010-01-03 23 views
8

Câu hỏi: Sản phẩm ngăn ngừa XSS (cross-site scripting) như đơn giản sử dụng strip_tags trên bất kỳ lĩnh vực đầu vào lưu và chạy htmlspecialchars trên bất kỳ hiển thị đầu ra ... và ngăn ngừa SQL Injection bằng cách sử dụng các câu lệnh chuẩn bị PDO PHP?là ngăn ngừa XSS và SQL Injection dễ dàng như việc thực hiện điều này

Dưới đây là một ví dụ:

// INPUT: Input a persons favorite color and save to database 
// this should prevent SQL injection (by using prepared statement) 
// and help prevent XSS (by using strip_tags) 
$sql = 'INSERT INTO TABLE favorite (person_name, color) VALUES (?,?)'; 
$sth = $conn->prepare($sql); 
$sth->execute(array(strip_tags($_POST['person_name']), strip_tags($_POST['color']))); 


// OUTPUT: Output a persons favorite color from the database 
// this should prevent XSS (by using htmlspecialchars) when displaying 
$sql = 'SELECT color FROM favorite WHERE person_name = ?'; 
$sth = $conn->prepare($sql); 
$sth->execute(array(strip_tags($_POST['person_name']))); 
$sth->setFetchMode(PDO::FETCH_BOTH); 
while($color = $sth->fetch()){ 
    echo htmlspecialchars($color, ENT_QUOTES, 'UTF-8'); 
} 
+0

Không hoàn toàn bắt được bạn - bạn sẽ truy cập mysql_query() giá trị $ save_to_database? Sau đó, bạn vẫn cần gọi 'mysql_real_escape_string()' trước khi bạn gửi truy vấn, nếu không bạn không được bảo vệ khỏi việc tiêm SQL (không phải là XSS, một lần nữa) – naivists

+2

@naivists: Bạn có chắc chắn về điều đó không? Anh ta đang sử dụng các câu lệnh chuẩn bị. – Erlend

Trả lời

8

Nó thậm chí còn đơn giản hơn. Chỉ cần htmlspecialchars() (với kiểu báo giá và bộ ký tự) trên đầu vào do người dùng điều khiển là đủ. strip_tags() chỉ hữu ích nếu bạn đã muốn vệ sinh dữ liệu trước khi xử lý/lưu trong cơ sở dữ liệu, thường không được sử dụng trong thế giới thực. Mã HTML không gây hại trong nguồn PHP, nhưng mã PHP có thể làm như vậy nếu bạn sử dụng eval() trên đầu vào do người dùng kiểm soát không được vệ sinh hoặc loại công cụ độc ác đó.

Tuy nhiên, điều này không giúp bạn tiết kiệm từ SQL injections, nhưng đó là một câu chuyện khác.

Cập nhật: để có được sạch đầu vào dùng từ yêu cầu để tránh magic quotes ở đầu vào sử dụng điều khiển, bạn có thể sử dụng chức năng sau:

function get_string($array, $index, $default = null) { 
    if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) { 
     return get_magic_quotes_gpc() ? stripslashes($value) : $value; 
    } else { 
     return $default; 
    } 
} 

mà có thể được sử dụng như:

$username = get_string($_POST, "username"); 
$password = get_string($_POST, "password"); 

(bạn có thể làm simliar cho get_number, get_boolean, get_array, v.v ...

Để chuẩn bị các truy vấn SQL để tránh SQL injections, làm:

$sql = sprintf(
    "SELECT id FROM user WHERE username = '%s' AND password = MD5('%s')", 
     mysql_real_escape_string($user), 
     mysql_real_escape_string($password) 
); 

Để hiển thị đầu vào người sử dụng kiểm soát để tránh XSS, làm:

echo htmlspecialchars($data, ENT_QUOTES, 'UTF-8'); 
+0

Làm cách nào để sửa đổi cũng bảo vệ tôi khỏi việc tiêm SQL ngoài XSS? – TimTim

+1

Sử dụng 'mysql_real_esacpe_string()': http://php.net/manual/en/function.mysql-real-escape-string.php. Hơn nữa, bạn cũng cần xem xét 'get_magic_quotes_gpc()'. Nếu điều này trả về đúng trên môi trường PHP, bạn cũng cần phải chạy 'stripslashes()' trên đầu vào. – BalusC

+0

Nếu tôi sử dụng các câu lệnh chuẩn bị PDO, điều đó có ngăn chặn việc tiêm SQL không? – TimTim

4

strip_tags là không cần thiết. Trong hầu hết các trường hợp, strip_tags chỉ gây khó chịu vì một số người dùng của bạn có thể muốn sử dụng <> trong văn bản của họ. Chỉ cần sử dụng htmlspecialchars (hoặc htmlentities nếu bạn thích) trước khi bạn echo các văn bản cho trình duyệt.

(Đừng quên mysql_real_esacpe_string trước khi bạn chèn bất cứ điều gì vào cơ sở dữ liệu của bạn!)

2

câu trả lời đơn giản: không có

Còn câu trả lời: Có nhiều cách để tiêm XSS mà strip_stags PHP không thể tránh.

Để bảo vệ tốt hơn thử HTML purifier

+0

Cảm ơn vì mẹo! Tôi không nghĩ đó là giải pháp duy nhất cho vấn đề chính xác này, nhưng nó tốt nếu tôi muốn cho phép một số định dạng HTML. –

+1

Hãy tưởng tượng chúng ta có một trang chỉ với '' Trong phần thân của nó. Những gì tiêm có thể ở đây? – naivists

+0

.. khi 'strip_tags()' được sử dụng * mà không có * 'htmlspecialchars()'. – BalusC

5

Nó phụ thuộc vào địa điểm và cách bạn muốn sử dụng các dữ liệu người dùng. Bạn cần phải biết bối cảnh bạn muốn chèn dữ liệu của mình vào và các ký tự meta của ngữ cảnh đó.

Nếu bạn chỉ muốn cho phép người dùng đặt văn bản lên trên trang web của mình, htmlspecialchars đủ để thoát khỏi các ký tự meta HTML.Nhưng nếu bạn muốn cho phép HTML nhất định hoặc muốn nhúng dữ liệu người dùng trong các phần tử HTML hiện tại (như URL vào yếu tố A/IMG), htmlspecialchars là không đủ vì bạn không ở trong ngữ cảnh HTML nữa mà trong ngữ cảnh URL.

Vì vậy, bước vào <script>alert("xss")</script> vào trường URL hình ảnh sẽ mang lại:

<img src="&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt" /> 

Nhưng vào javascript:alert("xss") sẽ thành công:

<img src="javascript:alert(&quot;xss&quot;)" /> 

Ở đây bạn nên có một cái nhìn tại tuyệt vời XSS (Cross Site Scripting) Cheat Sheet để xem những gì ngữ cảnh của bạn dữ liệu người dùng có thể được nhập vào.

+0

@Gumbo, bài đăng gốc đã cập nhật của tôi có bảo vệ tôi khỏi ví dụ của bạn về việc không sử dụng thẻ tập lệnh không? – TimTim

+1

@TimTim: Nó chỉ phụ thuộc vào ngữ cảnh mà bạn muốn sử dụng dữ liệu đó. – Gumbo

+0

@Gumbo làm thế nào để bạn ngăn chặn loại tấn công đó? Tôi đang đọc liên kết owasp mà bạn đã đưa ra nhưng tôi không thấy nó nói cách nào để ngăn chặn những cuộc tấn công đó .. –

3

Quy tắc chung/meme là "Bộ lọc đầu vào, đầu ra thoát". Sử dụng strip_tags trên đầu vào của bạn để xóa bất kỳ HTML nào là ý tưởng tốt cho lọc đầu vào, nhưng bạn nên càng nghiêm ngặt càng tốt trong đầu vào bạn cho phép. Ví dụ: nếu tham số đầu vào chỉ được coi là số nguyên, chỉ chấp nhận đầu vào số và luôn chuyển đổi số nguyên thành số nguyên trước khi thực hiện mọi thứ với số nguyên đó. Một thư viện lọc đầu vào được kiểm tra tốt sẽ giúp bạn rất nhiều ở đây; một trong đó không phải là cụ thể cho một khuôn khổ cụ thể là Inspekt (mà tôi đã viết, vì vậy tôi là một chút thiên vị).

Đối với đầu ra, htmlspecialcharsnên có thể thoát khỏi cuộc tấn công XSS, nhưng chỉ khi bạn vượt qua các thông số đúng. Bạn phải chuyển kiểu báo giá thoát bộ ký tự.

Nói chung, này nên loại bỏ các cuộc tấn công XSS:

$safer_str = htmlspecialchars($unsafe_str, ENT_QUOTES, 'UTF-8'); 

Nếu không đi qua ENT_QUOTES như tham số thứ hai, ký tự single-quote không được mã hóa. Ngoài ra, các cuộc tấn công XSS đã được chứng minh khi bộ ký tự chính xác không được thông qua (thường là UTF-8 sẽ đầy đủ). htmlspecialchars nên luôn gọi được gọi với ENT_QUOTES và tham số ký tự.

Lưu ý rằng PHP 5.2.12 có chứa bản sửa lỗi cho a multibyte XSS attack.

Bạn có thể thấy OWASP ESAPI PHP port thú vị và hữu ích, mặc dù phiên bản PHP chưa hoàn thành AFAIK.

+0

@ Funkatron, vậy bài viết gốc đã được cập nhật của tôi có bảo vệ tôi khỏi mọi điều xấu không? – TimTim

+0

Dường như tương đối an toàn, vâng. – Funkatron

+1

Tôi không nghĩ 'strip_tags' là một ý tưởng hay. Nó phá vỡ một số đầu vào hợp pháp, nhưng không đủ để bảo mật. Chỉ cần 'htmlspecialchars()' đủ và nó không bị mất. – Kornel

3

Có, sử dụng các câu lệnh chuẩn bị PDO bảo vệ khỏi việc tiêm SQL. Cuộc tấn công SQL injection dựa trên thực tế là dữ liệu được gửi bởi kẻ tấn công được coi là một phần của truy vấn. Ví dụ, kẻ tấn công gửi chuỗi "a" hoặc "a '=' a" làm mật khẩu của anh ấy. Thay vì toàn bộ chuỗi được so sánh với mật khẩu trong cơ sở dữ liệu, nó được bao gồm trong truy vấn, do đó truy vấn trở thành "SELECT * FROM users WHERE login = 'joe' AND password = 'a' hoặc 'a' = 'a' ". Phần đầu vào của kẻ tấn công được hiểu là một phần của truy vấn. Tuy nhiên trong trường hợp các câu lệnh chuẩn bị, bạn đang nói cụ thể cho SQL, phần nào là truy vấn và phần nào là dữ liệu (bằng cách thiết lập các tham số), vì vậy không có sự nhầm lẫn nào như vậy.

Không, việc sử dụng strip_tags sẽ không phải lúc nào cũng bảo vệ bạn khỏi tập lệnh chéo trang web. Hãy xem xét ví dụ sau. Giả sử trang của bạn chứa:

<script> 
location.href='newpage_<?php echo strip_tags($_GET['language']); ?>.html'; 
</script> 

Kẻ tấn công gửi yêu cầu bằng "ngôn ngữ" được đặt thành "'; somethingevil();'".strip_tags() trả về dữ liệu này như là (không có thẻ nào trong đó). Mã trang được sản xuất trở thành:

<script> 
location.href='newpage_';somethingevil();'.html'; 
</script> 

somethingevil() được thực thi. Thay thế somethingevil() bằng mã khai thác XSS thực tế.

Ví dụ cuối cùng của bạn với htmlspecialchars() sẽ bảo vệ chống lại điều này, bởi vì nó sẽ thoát khỏi dấu nháy đơn. Tuy nhiên, tôi đã nhìn thấy thậm chí các trường hợp dữ liệu do người dùng cung cấp bên trong mã JavaScript, nơi nó không nằm trong chuỗi được trích dẫn. Tôi nghĩ rằng đó là trong biến hoặc tên hàm. Trong trường hợp cuối cùng đó không có số lượng thoát sẽ có thể giúp đỡ. Tôi tin rằng tốt nhất là tránh sử dụng đầu vào của người dùng để tạo mã JavaScript.

+0

'