Tải bản đầy đủ (.pdf) (11 trang)

Bảy thói quen để viết các ứng dụng PHP an toàn

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (354.87 KB, 11 trang )

Bảo đảm an ninh trong PHP gồm các quan tâm an ninh cục bộ và từ xa. Phát hiện các thói quen mà các nhà phát triển
PHP nên rèn luyện để thực hiện các ứng dụng Web có cả hai đặc trưng trên.
Nathan Good sống tại vùng Twin Cities của bang Minnesota. Về chuyên môn, ông làm công việc phát triển phần mềm, kiến trúc phần mềm
và quản trị các hệ thống. Khi ông không viết phần mềm, ông rất thích xây dựng các máy chủ và máy tính cá nhân, đọc và làm việc với các
công nghệ mới và cố gắng khuyến khích bạn bè của mình chuyển sang phần mềm mã nguồn mở
31 07 2009
Khi nói đến an ninh, hãy nhớ rằng ngoài các vấn đề an ninh hệ điều hành và nền hệ thống thực tế, bạn
cần phải đảm bảo rằng bạn viết ứng dụng của bạn là an toàn. Khi bạn viết các ứng dụng PHP, hãy áp
dụng bảy thói quen này để đảm bảo rằng các ứng dụng của bạn là an toàn mức cao nhất có thể:
Kiểm tra hợp lệ đầu vào
Bảo vệ hệ thống tệp tin của bạn
Bảo vệ cơ sở dữ liệu của bạn
Bảo vệ dữ liệu phiên làm việc của bạn
Bảo vệ chống lại các sơ hở của kịch bản lệnh xuyên các trang (Cross-Site Scripting - XSS)
Kiểm tra các biểu mẫu gửi lên
Bảo vệ chống lại các giả mạo yêu cầu xuyên các trang (Cross-Site Request Forgeries - CSRF)
Kiểm tra hợp lệ đầu vào
Kiểm tra dữ liệu hợp lệ là thói quen quan trọng nhất mà bạn có thể tuân thủ khi nói về an ninh. Và khi nói
đến đầu vào, đơn giản là: Đừng tin tưởng người sử dụng. Người sử dụng của bạn có lẽ là người tốt, và
hầu hết họ có lẽ sử dụng ứng dụng của bạn đúng như bạn đã mong đợi. Tuy nhiên, bất cứ khi nào có cơ
hội nhập đầu vào, có nghĩa là cũng có cơ hội để nhập đầu vào xấu, thực sự là xấu. Là một nhà phát triển
ứng dụng, bạn phải bảo vệ ứng dụng của mình trước đầu vào xấu. Việc xem xét cẩn thận đầu vào từ
người sử dụng của bạn đang hướng tới đâu và đó phải là cái gì sẽ cho phép bạn xây dựng một ứng
dụng vững chãi, an toàn.
Mặc dù tương tác hệ thống tệp tin và cơ sở dữ liệu sẽ được trình bày sau, dưới đây là các lời khuyên
chung về kiểm tra hợp lệ, bao gồm mọi loại:
Sử dụng danh sách các giá trị hợp lệ (white-listed)
Luôn luôn kiểm tra hợp lệ lại các lựa chọn bị hạn chế
Sử dụng các hàm thoát lập sẵn
developerWorks tiếng Việt Các chủ đề kỹ thuật Nguồn mở Thư viện Kỹ thuật
Bảy thói quen để viết các ứng dụng PHP an toàn


Tăng cường an ninh cho các ứng dụng web của bạn
Kiểm tra kiểu dữ liệu đúng đắn, ví dụ như là các số
Các giá trị trong danh sách trắng (white-listed) là các giá trị được chấp nhận, đối lập với các giá trị thuộc
danh sách đen (black-listed) là không được chấp nhận. Sự phân biệt là ở chỗ, thông thường khi kiểm tra
hợp lệ, danh sách hoặc dải các giá trị khả dĩ nhỏ hơn danh sách các giá trị không hợp lệ vì nhiều giá trị
không hợp lệ còn chưa biết hoặc rất bất ngờ.
Khi bạn đang thực hiện kiểm tra hợp lệ, nên nhớ rằng thường dễ hình dung và kiểm tra hợp lệ những cái
mà ứng dụng đó cho phép thay vì cố gắng bảo vệ chống lại tất cả các giá trị chưa biết. Ví dụ, để giới hạn
các giá trị trong một trường chỉ là các số, hãy viết ra một thủ tục (routine) bảo đảm đầu vào tất cả phải là
số. Đừng viết thủ tục để tìm kiếm các giá trị không phải là số và đánh dấu nó là không hợp lệ nếu tìm
thấy.
Bảo vệ hệ thống tệp tin của bạn
Vào tháng Bảy năm 2000, một trang web đã để lọt dữ liệu của khách hàng trong các tệp tin trên một máy
chủ Web. Một người xem truy cập vào trang web đó đã điều khiển URL để xem được các tệp tin có chứa
dữ liệu. Mặc dù các tệp tin này bị đặt sai vị trí, ví dụ này nhấn mạnh tầm quan trọng của việc bảo vệ hệ
thống tệp tin của bạn chống lại những kẻ thâm nhập.
Nếu ứng dụng PHP làm bất cứ điều gì với các tệp tin và có dữ liệu biến đổi mà người sử dụng có thể
nhập vào, hãy cẩn thận rằng bạn phải lau chùi sạch sẽ dữ liệu đầu vào của người sử dụng để đảm bảo
rằng người sử dụng không thể làm được bất cứ điều gì đối với hệ thống tệp tin mà bạn không muốn họ
làm. Liệt kê 1 cho thấy một thí dụ về một trang web PHP để tải xuống một hình ảnh khi cung cấp tên.
Liệt kê 1. Tải xuống một tệp tin
<?php
if ($_POST['submit'] == 'Download') {
$file = $_POST['fileName'];
header("Content-Type: application/x-octet-stream");
header("Content-Transfer-Encoding: binary");
header("Content-Disposition: attachment; filename=\"" . $file . "\";" );
$fh = fopen($file, 'r');
while (! feof($fh))
{

echo(fread($fh, 1024));
}
fclose($fh);
} else {
echo("<html><head><");
echo("title>Guard your filesystem</title></head>");
echo("<body><form id=\"myFrom\" action=\"" . $_SERVER['PHP_SELF'] .
"\" method=\"post\">");
echo("<div><input type=\"text\" name=\"fileName\" value=\"");
echo(isset($_REQUEST['fileName']) ? $_REQUEST['fileName'] : '');
echo("\" />");
echo("<input type=\"submit\" value=\"Download\" name=\"submit\" /></div>");
echo("</form></body></html>");
}
Như bạn có thể thấy, kịch bản tương đối nguy hiểm trong Liệt kê 1 đưa ra phục vụ bất kỳ tệp tin nào mà
máy chủ Web có quyền đọc, kể cả các tệp tin trong thư mục phiên làm việc (xem phần "Bảo vệ dữ liệu
phiên làm việc của bạn") và thậm chí một số tệp tin hệ thống như /etc/passwd. Thí dụ này có một hộp
văn bản trong đó người sử dụng có thể gõ nhập vào tên tệp tin dùng làm ví dụ, nhưng tên tệp tin đó cũng
có thể được cung cấp một cách dễ dàng trong chuỗi truy vấn.
Việc cấu hình cho phép truy cập hệ thống tệp tin tùy theo đầu vào của người sử dụng là nguy hiểm, vì
vậy tốt nhất là tránh hoàn toàn việc đó bằng cách thiết kế ứng dụng của bạn để nó sử dụng một cơ sở
dữ liệu và các tên tệp tin được tạo ra và giấu kín. Tuy nhiên, không phải lúc nào cũng có thể làm thế. Liệt
kê 2 cung cấp một thí dụ về một thủ tục kiểm tra hợp lệ tên tệp tin. Nó sử dụng các biểu thức chính quy
để đảm bảo rằng chỉ các ký tự hợp lệ là được sử dụng trong tên tệp tin và đặc biệt kiểm tra các ký tự
chấm chấm:
Liệt kê 2. Kiểm tra hợp lệ với các ký tự trong tên tệp tin
function isValidFileName($file) {
/* don't allow and allow any "word" character \ / */
return preg_match('/^(((?:\.)(?!\.))|\w)+$/', $file);
}

Bảo vệ cơ sở dữ liệu của bạn
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
Lưu mật khẩu

Mật khẩu sẽ tuyệt đối không bao giờ
được lưu giữ ở dạng văn bản rõ ở bất kỳ
nơi nào — không được nằm trong một cơ
sở dữ liệu, phiên làm việc, hệ thống tệp
tin, hoặc ở bất kỳ dạng nào khác. Cách
tốt nhất để xử lý các mật khẩu là lưu
chúng đã mã hóa và so sánh với các mật
khẩu đã mã hóa với nhau. Mặc dù điều
này có vẻ là hiển nhiên, song việc lưu giữ
chúng ở dạng văn bản rõ dường như
được làm khá nhiều trong thực tế. Bất cứ
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.
Bảo vệ phiên làm việc của bạn
Theo mặc định, thông tin phiên làm việc trong PHP được viết vào một thư mục tạm thời. Hãy xem xét
biểu mẫu trong Liệt kê 5, nó cho thấy cách lưu một mã nhận dạng người sử dụng và số tài khoản trong
một phiên làm việc.
Liệt kê 5. Lưu trữ dữ liệu trong phiên
<?php
session_start();
?>
<html>
<head>
<title>Storing session information</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
$_SESSION['userName'] = $_POST['userName'];
$_SESSION['accountNumber'] = $_POST['accountNumber'];

}
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
<div><input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="userName"
value="<?php echo(isset($_POST['userName']) ? $_POST['userName'] : ''); ?>" />
<br />
<input type="text" name="accountNumber"
value="<?php echo(isset($_POST['accountNumber']) ?
$_POST['accountNumber'] : ''); ?>" />
<br />
<input type="submit" value="Save" name="submit" /></div>
</form>
</body>
</html>
Liệt kê 6 cho thấy nội dung của thư mục /tmp.
Liệt kê 6. Các tệp tin phiên trong thư mục /tmp
-rw 1 _www wheel 97 Aug 18 20:00 sess_9e4233f2cd7cae35866cd8b61d9fa42b
Như bạn có thể thấy, tệp tin phiên, khi được in ra (xem Liệt kê 7), chứa các thông tin trong một định dạng
khá dễ đọc. Vì tệp tin phải đọc được và viết được đối với người sử dụng máy chủ web, các tệp tin phiên
này có thể tạo ra một vấn đề lớn đối với bất cứ người nào trên một máy chủ chia sẻ. Người nào đó
không phải là bạn có thể viết một kịch bản lệnh đọc các tệp tin này để họ có thể thử lợi dụng phiên làm
việc đó.
Liệt kê 7. Nội dung của một tệp tin phiên
userName|s:5:"ngood";accountNumber|s:9:"123456789";
Bạn có thể làm hai điều để bảo vệ dữ liệu phiên của bạn. Trước tiên
là mã hóa mọi thứ mà bạn đưa vào phiên. Tuy nhiên chỉ riêng việc
bạn đã mã hóa dữ liệu không có nghĩa là nó đã an toàn trọn vẹn, do
đó hãy cẩn thận, đừng tin tưởng vào việc này như là phương tiện

duy nhất của bạn để bảo vệ phiên làm việc của mình. Có cách khác
là lưu dữ liệu phiên của bạn ở một nơi khác, ví dụ như một cơ sở
dữ liệu. Bạn vẫn phải đảm bảo rằng bạn đang khóa kín cơ sở dữ
liệu của bạn, nhưng cách tiếp cận này giải quyết được hai vấn đề:
Trước nhất, nó đặt dữ liệu của bạn vào một nơi an toàn hơn một hệ
thống tệp tin chia sẻ; thứ hai, nó cho phép ứng dụng của bạn mở
khi nào bạn sử dụng một trang web mà
có thể gửi cho bạn mật khẩu của bạn
thay vì việc đặt lại, điều đó có nghĩa là
hoặc mật khẩu được lưu ở dạng văn bản
rõ hoặc đã có mã lệnh sẵn để giải mã mật
khẩu nếu nó được mật mã hóa. Ngay cả
ở trường hợp sau, mã lệnh để giải mã có
thể tìm thấy và khai thác được.
rộng trải ra bao gồm nhiều máy chủ web dễ dàng hơn với các phiên
được chia sẻ xuyên qua nhiều máy chủ.
Để thực hiện ghi lưu bền vững các dữ liệu về phiên làm việc của
chính bạn, xem hàm session_set_save_handler() trong PHP.
Dùng nó, bạn có thể lưu trữ thông tin phiên trong một cơ sở dữ liệu
hoặc triển khai thực hiện một trình xử lý (handler) để mã hoá và giải
mã toàn bộ các dữ liệu của bạn. Liệt kê 8 cung cấp một thí dụ về
cách sử dụng hàm này và các hàm khung cho việc triển khai thực hiện. Bạn cũng có thể kiểm tra các thí
dụ về cách sử dụng một cơ sở dữ liệu trong phần Tài nguyên.
Liệt kê 8. Ví dụ về hàm session_set_save_handler()
function open($save_path, $session_name)
{
/* custom code */
return (true);
}
function close()

{
/* custom code */
return (true);
}
function read($id)
{
/* custom code */
return (true);
}
function write($id, $sess_data)
{
/* custom code */
return (true);
}
function destroy($id)
{
/* custom code */
return (true);
}
function gc($maxlifetime)
{
/* custom code */
return (true);
}
session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
Bảo vệ chống lại các lỗ hổng XSS
Các lỗ hổng XSS chiếm một tỷ lệ lớn trong tất cả các lỗ hổng về trang web được ghi chép lại trong năm
2007 (xem Tài nguyên). Một lỗ hổng XSS xuất hiện khi một người sử dụng có khả năng bơm mã HTML
vào các trang web của bạn. Mã HTML có thể mang theo mã JavaScript bên trong các thẻ kịch bản (script
tags), bằng cách đó cho phép JavaScript chạy bất cứ khi nào một trang được rút ra. Biểu mẫu trong Liệt

kê 9 có thể đại diện cho một diễn đàn, trang mạng biên tập tự do (wiki), mạng xã hội, hoặc bất kỳ trang
web nào khác thông dụng để gõ nhập văn bản.
Liệt kê 9. Biểu mẫu để nhập vào văn bản
<html>
<head>
<title>Your chance to input XSS</title>
</head>
<body>
<form id="myFrom" action="showResults.php" method="post">
<div><textarea name="myText" rows="4" cols="30"></textarea><br />
<input type="submit" value="Delete" name="submit" /></div>
</form>
</body>
</html>
Liệt kê 10 chứng tỏ cách biểu mẫu này in ra được các kết quả, cho phép tấn công bằng XSS.
Liệt kê 10. showResults.php
<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo($_POST['myText']);
echo("</p>");
?>
</body>
</html>
Liệt kê 11 đưa ra một thí dụ cơ sở trong đó các cửa sổ mới bật ra mở đến trang chủ của Google. Nếu

ứng dụng web của bạn không bảo vệ chống lại các tấn công bằng XSS, thì giới hạn thiệt hại duy nhất chỉ
còn là sức tưởng tượng của kẻ thâm nhập mà thôi. Ví dụ, một ai đó có thể thêm vào một liên kết mà bắt
chước kiểu dáng của trang web đó để lừa đảo (phishing) (xem Tài nguyên).
Liệt kê 11. Mẫu văn bản đầu vào độc hại
<script type="text/javascript">myRef = window.open('','mywin',
'left=20,top=20,width=500,height=500,toolbar=1,resizable=0');</script>
Để tự bảo vệ bạn chống lại các tấn công XSS, hãy lọc đầu vào của bạn thông qua hàm
htmlentities() bất cứ khi nào giá trị của một biến được in đến đầu ra. Hãy nhớ làm theo thói quen
đầu tiên về kiểm tra hợp lệ dữ liệu đầu vào bằng các giá trị trong danh sách trắng trong ứng dụng web
của bạn đối với tên, địa chỉ email, số điện thoại, và thông tin về hoá đơn thanh toán.
Một phiên bản an toàn hơn nhiều của trang để hiển thị văn bản đầu vào như dưới đây.
Liệt kê 12. Một biểu mẫu an toàn hơn
<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo(htmlentities($_POST['myText']));
echo("</p>");
?>
</body>
</html>
Bảo vệ chống lại việc gửi lên (post) không hợp lệ
Nhại mẫu (Form spoofing) là khi một ai đó thực hiện gửi lên đến một trong các biểu mẫu của bạn từ một
nơi nào đó mà bạn không mong đợi. Cách dễ nhất để nhại mẫu chỉ đơn giản là tạo ra một trang web đệ
trình một biểu mẫu, chuyển theo tất cả các giá trị. Do các ứng dụng web là phi trạng thái (stateless), nên
không có cách nào để chắc chắn tuyệt đối là dữ liệu đã được gửi lên từ nơi mà bạn muốn nó đến từ đó.

Mọi thứ từ các địa chỉ IP cho đến tên máy chủ, cuối cùng rồi đều có thể bị nhại. Liệt kê 13 hiển thị một
biểu mẫu điển hình cho phép bạn nhập thông tin.
Liệt kê 13. Một biểu mẫu để xử lý văn bản
<html>
<head>
<title>Form spoofing example</title>
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
echo("<p>I am processing your text: ");
echo($_POST['myText']);
echo("</p>");
}
?>
</body>
</html>
Liệt kê 14 cho thấy một biểu mẫu sẽ được gửi đến biểu mẫu trong Liệt kê 13. Để thử việc này, bạn có
thể đặt mẫu đó lên một trang web, sau đó ghi lưu mã trong Liệt kê 14 như một tài liệu HTML trên máy
tính của bạn. Khi bạn đã lưu lại biểu mẫu này, hãy mở nó ra trong một trình duyệt. Sau đó bạn có thể
điền dữ liệu vào và đệ trình biểu mẫu đó rồi quan sát trong khi dữ liệu được xử lý.
Liệt kê 14. Một biểu mẫu để thu thập dữ liệu của bạn
<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="processStuff.php" method="post">
<select name="answer">
<option value="Yes">Yes</option>

<option value="No">No</option>
</select>
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>
Tác động tiềm tàng của việc nhại mẫu thực ra là ở chỗ nếu bạn có một biểu mẫu mà có các hộp thả
xuống, nút radio, hộp kiểm, hoặc các đầu vào hạn chế khác, những hạn chế đó không có ý nghĩa gì cả
nếu biểu mẫu đó bị giả mạo. Xem xét mã trong Liệt kê 15, trong đó chứa một biểu mẫu với dữ liệu không
hợp lệ.
Liệt kê 15. Một biểu mẫu với dữ liệu không hợp lệ
<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="
method="post"><input type="text" name="answer"
value="There is no way this is a valid response to a yes/no answer " />
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>
Nếu bạn có một hộp thả xuống hoặc một nút radio, hạn chế người sử dụng chỉ có một số lượng đầu vào
nhất định, bạn có thể bị thuyết phục rằng không phải lo lắng về việc kiểm tra hợp lệ đầu vào. Rốt cuộc,
biểu mẫu đầu vào của bạn bảo đảm rằng người sử dụng chỉ có thể nhập vào một số dữ liệu nhất định,
đúng không? Để hạn chế việc nhại mẫu, hãy lập ra các biện pháp để bảo đảm rằng những người gửi dữ
liệu lên đúng là những người khai nhận rằng họ là những người đó. Một kỹ thuật mà bạn có thể sử dụng
là thẻ bài sử dụng một lần (single-use token), nó không làm cho việc giả mạo mẫu của bạn bất khả thi
nhưng làm cho nó trở thành một điều rắc rối kinh khủng. Vì thẻ bài thay đổi mỗi khi mẫu được rút xuống,

một kẻ xâm nhập tương lai cần phải lấy một cá thể của biểu mẫu đang gửi, rút thẻ bài, và đặt nó vào
phiên bản giả mạo của biểu mẫu đó. Kỹ thuật này làm cho rất khó có khả năng một ai đó lập ra một biểu
mẫu web lâu dài để gửi các yêu cầu không mong muốn đến ứng dụng của bạn. Liệt kê 16 đưa ra một thí
dụ về một thẻ bài biểu mẫu dùng một lần.
Liệt kê 16. Sử dụng một thẻ bài biểu mẫu một lần
<?php
session_start();
?>
<html>
<head>
<title>SQL Injection Test</title>
</head>
<body>
<?php
echo 'Session token=' . $_SESSION['token'];
echo '<br />';
echo 'Token from form=' . $_POST['token'];
echo '<br />';
if ($_SESSION['token'] == $_POST['token']) {
/* cool, it's all good create another one */
} else {
echo '<h1>Go away!</h1>';
}
$token = md5(uniqid(rand(), true));
$_SESSION['token'] = $token;
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
<div><input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="text" name="myText"

value="<?php echo(isset($_POST['myText']) ? $_POST['myText'] : ''); ?>" />
<input type="submit" value="Save" name="submit" /></div>
</form>
</body>
</html>
Bảo vệ chống lại CSRF
Các giả mạo truy vấn xuyên các trang (các tấn công CSRF-Cross-Site Request Forgeries) khai thác các
lợi thế về quyền ưu tiên của người sử dụng để thực hiện tấn công. Trong một cuộc tấn công CSRF,
người sử dụng của bạn có thể dễ dàng trở thành các kẻ đồng loã không bị nghi ngờ. Liệt kê 17 cung cấp
một thí dụ về một trang web thực hiện một số hành động. Trang web này tìm kiếm thông tin đăng nhập
của người sử dụng từ cookie. Khi mà cookie này hợp lệ, trang web sẽ xử lý yêu cầu.
Liệt kê 17. Một thí dụ của CSRF
<img src=" />
Các cuộc tấn công CSRF thường được thực hiện dưới dạng các thẻ <img> vì trình duyệt gọi URL một
cách không ý thức để lấy hình ảnh. Tuy nhiên, nguồn hình ảnh dễ dàng có thể chỉ là URL của một trang
web trên cùng một site, thực hiện các việc xử lý nào đó dựa trên các tham số chuyển cho nó. Khi thẻ
<img> này được đặt trong một cuộc tấn công XSS — cũng là các tấn công phổ biến nhất được ghi chép
lại — người sử dụng dễ dàng có thể làm một việc gì đó với quyền ưu tiên được cấp mà không biết mình
đã làm — như vậy, có thể giả mạo.
Để tự bảo vệ bạn chống lại CSRF, hãy sử dụng cách tiếp cận thẻ bài sử dụng một lần mà bạn áp dụng
tuân theo thói quen xác minh các biểu mẫu gửi lên. Ngoài ra, sử dụng biến hiển $_POST thay vì
$_REQUEST. Liệt kê 18 trình bày một ví dụ xấu về trang web mà xử lý y như thế — cho dù trang web đó
được gọi bởi một yêu cầu GET hay bởi vì có một biểu mẫu gửi lên đến nó.
Liệt kê 18. Lấy dữ liệu từ $_REQUEST
<html>
<head>
<title>Processes both posts AND gets</title>
</head>
<body>
<?php

if ($_REQUEST['submit'] == 'Save') {
echo("<p>I am processing your text: ");
echo(htmlentities($_REQUEST['text']));
echo("</p>");
}
?>
</body>
</html>
Liệt kê 19 cho thấy một phiên bản đã làm sạch của trang này, sẽ chỉ làm việc khi POST biểu mẫu.
Liệt kê 19. Lấy dữ liệu chỉ từ $_POST
<html>
<head>
<title>Processes both posts AND gets</title>
Tài nguyên
Học tập
Đọc tài liệu hướng dẫn "Khóa các ứng dụng PHP của bạn" trên
developerWorks để tìm hiểu bốn quy tắc an ninh mà nhà phát triển không
được vi phạm.
Đọc "Mật mã hoá PHP cho người bình thường" để tìm hiểu cách bảo vệ dữ
liệu trong các ứng dụng PHP.
Xem PHP Security Consortium để có các thông tin tuyệt vời về an ninh PHP.
Xem trang PHP security tại trang web chính thức của PHP để nhận được các
lời khuyên về an ninh.
Tìm hiểu thêm về việc thực hiện các trình xử lý phiên làm việc tuỳ chỉnh được
từ mục session_set_save_handler trên trang web chính thức của PHP.
Đọc mục XSS rất xuất sắc của Wikipedia.
Đọc bài Essential PHP Security của Chris Shiflett có sẵn trên PHP.org.
PHP.net là nguồn tài nguyên trung tâm cho các nhà phát triển PHP.
Xem "Recommended PHP reading list."
Duyệt toàn bộ các nội dung PHP trên developerWorks.

Mở rộng kỹ năng PHP của bạn bằng cách xem các nguồn tài nguyên dự án
PHP developerWorks của IBM .
Để nghe phỏng vấn và các cuộc thảo luận thú vị đối với các nhà phát triển
phần mềm, xem developerWorks podcasts.
Bạn sử dụng cơ sở dữ liệu với PHP? Hãy thử Zend Core for IBM, đó là một
môi trường phát triển và chạy sản xuất PHP liền khối, sẵn để dùng ngay, dễ
Vùng dữ liệu trên
developerWorks
Khám phá các bài viết xoay
quanh lĩnh vực dữ liệu, Quản lý
hệ thống thông tin
Vùng mã nguồn mở trên
developerWorks
Xem các bài viết về HTML, CSS,
JavaScript,
Điện toán đám mây
Tìm hiểu về điện toán đám mây
</head>
<body>
<?php
if ($_POST['submit'] == 'Save') {
echo("<p>I am processing your text: ");
echo(htmlentities($_POST['text']));
echo("</p>");
}
?>
</body>
</html>
Kết luận
Bắt đầu với bảy thói quen này để viết các ứng dụng web PHP an toàn hơn sẽ giúp bạn tránh bị trở thành

nạn nhân dễ dàng của các tấn công độc hại. Giống như nhiều thói quen, chúng lúc đầu có vẻ như rắc rối,
nhưng chúng trở nên tự nhiên hơn theo thời gian.
Nên nhớ rằng thói quen đầu tiên là chủ chốt: Hãy kiểm tra hợp lệ đầu vào của bạn. Khi bạn chắc chắn
rằng đầu vào của bạn không chứa các giá trị xấu, bạn có thể chuyển tiếp sang việc bảo vệ hệ thống tệp
tin, cơ sở dữ liệu, và phiên làm việc của bạn. Cuối cùng, hãy chắc chắn rằng mã PHP của bạn kiên
cường kháng cự được các tấn công XSS, nhại mẫu, và các tấn công CSRF. Một cách tiếp cận có kỷ luật
để hình thành những thói quen ấy sẽ khởi đầu một con đường dài hướng đến việc phòng ngừa các tấn
công dễ dàng.
dàng cài đặt và có hỗ trợ DB2 V9 của IBM.
Theo sát các sự kiện kỹ thuật và phát tin trên web của developerWorks.
Xem qua các hội nghị, trưng bày thương mại, các buổi phát tin trên mạng và
các Sự kiện khác trên khắp thế giới sắp diễn ra mà các nhà phát triển mã
nguồn mở của IBM quan tâm đến.
Hãy truy cập vào Open source zone của developerWorks để có các thông tin
hướng dẫn cách làm, các công cụ, và các dự án cập nhật, giúp bạn phát triển
với các công nghệ mã nguồn mở và sử dụng chúng với các sản phẩm của
IBM.
Theo dõi và tìm hiểu về IBM và các công nghệ mã nguồn mở và các chức
năng của sản phẩm qua các trình diễn miến phí theo yêu cầu trên
developerWorks (developerWorks On demand demos).
Lấy sản phẩm và công nghệ
Đổi mới dự án phát triển mã nguồn mở tiếp theo của bạn với phần mềm dùng
thử của IBM, sẵn có để tải về hoặc trên đĩa DVD.
Tải về các phiên bản đánh giá sản phẩm của IBM và hãy bắt tay bạn vào các
công cụ phát triển ứng dụng và các sản phẩm phần mềm tầng giữa từ DB2®,
Lotus®, Rational®, Tivoli® và WebSphere®.
Thảo luận
Tham gia vào các developerWorks blogs và gia nhập cộng đồng
developerWorks.
Tham gia vào Diễn đàn PHP developerWorks: Phát triển các ứng dụng PHP

với các sản phẩm quản lý thông tin của IBM (DB2, IDS).

×