Bảo vệ cơ sở dữ liệu của bạn trong PHP MYSQL
Vào tháng Tư năm 2008, Cục quản lý nhà tù (Department of Corrections) của một bang của Mỹ đã để rò rỉ dữ liệu nhạy cảm vì lý do tên cột SQL được sử dụng trong chuỗi vấn tin. Chỗ sơ hở này cho phép những người sử dụng ác ý chọn được (select) những cột nào muốn hiển thị, đưa ra các trang, và lấy dữ liệu. Vụ rò rỉ này cho thấy rằng người sử dụng có thể tính toán ra được các cách để làm cho đầu vào của họ làm những việc mà các nhà phát triển ứng dụng chắc chắn không lường trước được và nhấn mạnh sự cần thiết phải bảo vệ một cách cẩn thận chống lại các cuộc tấn công bằng bơm vào SQL (SQL injection).
Liệt kê 3 cho thấy một thí dụ của một kịch bản chạy một lệnh SQL. Trong thí dụ này, lệnh SQL là một lệnh động, có thể để lọt cùng một kiểu tấn công đó. Chủ nhân của biểu mẫu này có thể đã nghĩ rằng chúng là an toàn vì họ đã hạn chế các tên cột chỉ trong một danh sách chọn. Tuy nhiên, mã này bỏ qua sự chú ý nói trong thói quen cuối cùng về việc nhại mẫu (form spoofing) — chỉ vì mã hạn chế việc lựa chọn chỉ trong các hộp thả xuống không có nghĩa rằng một ai đó không thể gửi lên một biểu mẫu với bất cứ cái gì mà họ muốn trong đó (kể cả một dấu sao [
*]).Liệt kê 3. Thi hành một lệnh SQL
<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
<div><input type="text" name="account_number"
value="<?php echo(isset($_POST['account_number']) ?
$_POST['account_number'] : ''); ?>" />
<select name="col">
<option value="account_number">Account Number</option>
<option value="name">Name</option>
<option value="address">Address</option>
</select>
<input type="submit" value="Save" name="submit" /></div>
</form>
<?php
if ($_POST['submit'] == 'Save') {
/* do the form processing */
$link = mysql_connect('hostname', 'user', 'password') or
die ('Could not connect' . mysql_error());
mysql_select_db('test', $link);
$col = $_POST['col'];
$select = "SELECT " . $col . " FROM account_data WHERE account_number = "
. $_POST['account_number'] . ";" ;
echo '<p>' . $select . '</p>';
$result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');
echo '<table>';
while ($row = mysql_fetch_assoc($result)) {
echo '<tr>';
echo '<td>' . $row[$col] . '</td>';
echo '</tr>';
}
echo '</table>';
mysql_close($link);
}
?>
</body>
</html>
Vì vậy, để hình thành thói quen bảo vệ cơ sở dữ liệu của bạn, tránh mã SQL động càng nhiều càng tốt. Nếu bạn không thể tránh được mã SQL động, đừng sử dụng trực tiếp đầu vào đối với các cột. Liệt kê 4 hiển thị một thí dụ về năng lực khi bổ sung một thủ tục kiểm tra hợp lệ đơn giản đối với trường số tài khoản để đảm bảo rằng nó không thể là một dữ liệu không-phải-số, đồng thời sử dụng các tên cột tĩnh.
Liệt kê 4. Bảo vệ bằng kiểm tra hợp lệ và mysql_real_escape_string()
<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
<div><input type="text" name="account_number"
value="<?php echo(isset($_POST['account_number']) ?
$_POST['account_number'] : ''); ?>" /> <input type="submit"
value="Save" name="submit" /></div>
</form>
<?php
function isValidAccountNumber($number)
{
return is_numeric($number);
}
if ($_POST['submit'] == 'Save') {
/* Remember habit #1--validate your data! */
if (isset($_POST['account_number']) &&
isValidAccountNumber($_POST['account_number'])) {
/* do the form processing */
$link = mysql_connect('hostname', 'user', 'password') or
die ('Could not connect' . mysql_error());
mysql_select_db('test', $link);
$select = sprintf("SELECT account_number, name, address " .
" FROM account_data WHERE account_number = %s;",
mysql_real_escape_string($_POST['account_number']));
echo '<p>' . $select . '</p>';
$result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');
echo '<table>';
while ($row = mysql_fetch_assoc($result)) {
echo '<tr>';
echo '<td>' . $row['account_number'] . '</td>';
echo '<td>' . $row['name'] . '</td>';
echo '<td>' . $row['address'] . '</td>';
echo '</tr>';
}
echo '</table>';
mysql_close($link);
} else {
echo "<span style=\"font-color:red\">" .
"Please supply a valid account number!</span>";
}
}
?>
</body>
</html>
Ví dụ này cũng cho thấy việc sử dụng hàm
mysql_real_escape_string(). Hàm này chải sạch một cách đúng đắn đầu vào của bạn, sao cho nó không còn bao gồm các ký tự không hợp lệ. Nếu bạn dựa vào magic_quotes_gpc, xin báo trước là nó đã lạc hậu và sẽ được loại bỏ trong PHP V6. Bây giờ hãy tránh dựa vào nó và viết các ứng dụng PHP của bạn an toàn mà không cần đến nó. Ngoài ra, hãy nhớ rằng nếu bạn đang sử dụng một ISP, có nhiều khả năng là magic_quotes_gpc không được kích hoạt.
Cuối cùng, trong ví dụ được cải tiến, bạn có thể thấy rằng lệnh SQL và đầu ra không bao gồm việc lựa chọn cột động. Bằng cách này, nếu bạn sau này thêm cột vào bảng mà có các thông tin khác nhau, bạn có thể in chúng ra. Nếu bạn đang sử dụng một khung công tác để làm việc với cơ sở dữ liệu của bạn, có nhiều khả năng là khung công tác của bạn đã kiểm tra hợp lệ SQL cho bạn rồi. Hãy kiểm tra tài liệu về khung công tác của bạn xem đúng như thế không; nếu bạn vẫn chưa chắc chắn, hãy thực hiện việc kiểm tra hợp lệ với các lỗi về an toàn. Thậm chí nếu bạn đang sử dụng một khung công tác để tương tác cơ sở dữ liệu, bạn vẫn cần phải thực hiện những kiểm tra hợp lệ khác.
Không có nhận xét nào:
Đăng nhận xét