Ru-Board.club
← Вернуться в раздел «Web-программирование»

» Безопасное программирование на PHP

Автор: israel_rider
Дата сообщения: 01.07.2009 00:17
Пипл, помогите пожалуйста!
Скопируйте мне, если у кого есть готовый, кусок РНР кода, который выполняет все проверки безопасности, когда я организовываю для посетителей на сайте загрузку фотографий через НТМЛ форму. Чтобы злобный хакер вместо фотки не послал бы мне какой нибудь подлый скрипт.... Или ещё что нибудь в этом роде....
Автор: Cheery
Дата сообщения: 01.07.2009 00:20
israel_rider

Цитата:
Чтобы злобный хакер вместо фотки не послал бы мне какой нибудь подлый скрипт....

проверяйте расширение +
http://us2.php.net/manual/en/function.image-type-to-mime-type.php
или инфа из
http://us2.php.net/manual/en/function.getimagesize.php
Автор: israel_rider
Дата сообщения: 01.07.2009 00:38
Вот, сделал поиск на "getimagesize", и нашёл в точности то, что искал!

http://forum.dklab.ru/viewtopic.php?t=26754
Автор: israel_rider
Дата сообщения: 02.07.2009 07:51
Уважаемые Проффессионалы! Вот что у меня в результате получилось. Был бы счастлив выслушать ваши замечания.

<?php
if (!isset($_POST['fotobook'])) header("Location:book.php");      // Если юзер нажал кнопку "Загрузка файлов" что бы загрузить файл
if ($_FILES["imyfaila"]["size"] > 1024*2*1024) { // Проверяем размер
    echo "<h1 STYLE='color:red;'>Размер файла превышает 2 мегабайта.</h1><h2><a href=# onClick='history.back()'>Вернуться к отправке</а></h2>";
    exit();
}    
$prvrkimya = trim($_FILES["imyfaila"]["name"]); // Убираем пробелы с начала и конца оригинального имени фотки
$prvrkimya = substr($prvrkimya, -15); // Обрезаем оригинальное имя до 15-и знаков с конца
if (stristr($prvrkimya, '.') !== '.jpg') { // Проверяем расширение оригинального имени
    echo "<h1 STYLE='color:red;'>Это походу не фотка ни хрена... </h1><h2><a href=# onClick='history.back()'>Вернуться к отправке</а></h2>";
    exit();
}    
$prvrkfaila = getimagesize($_FILES['imyfaila']['tmp_name']);//Проверяем, не (removed) ли с размером и расширением подделов "Content-Type"
if ($prvrkfaila > 1024*2*1024 or $prvrkfaila['mime'] != 'image/jpg') {
    echo "<h1 STYLE='color:red;'>Чёто не тое... </h1><h2><a href=# onClick='history.back()'>Вернуться к отправке</а></h2>";
    exit();    
}
move_uploaded_file($_FILES['imyfaila']['tmp_name'], "knigajiz/vremenni.jpg"); // Если фотка всё выдержала, помещаем её в папку под временным именем
if($_FILES['imyfaila']['error'] > 0) {
echo "<h1 STYLE='color:red;'>Есть ошибки</h1><h2><a href=# onClick='history.back()'>Вернуться к отправке</а></h2>";
    exit();    
}
unlink($_FILES['image']['tmp_name']; // Уничтожаем фотку во временной директории
?>
Автор: zerkms
Дата сообщения: 02.07.2009 10:33
israel_rider
1. непонятна последняя проверка. зачем она нужна, если перед ней мы уже сделали move_uploaded_file?
2. зачем unlink в конце?
3. лапша %)
4. тип файла нужно брать не из mime, а из того, что возвращает getimagesize
5. if ($prvrkfaila > 1024*2*1024 в переменной массив, а не размер в байтах.
6. расширение лучше брать из pathinfo()
7. имена всех переменных поменять на релевантные и переведённые на английский язык
8. зачем размер проверять дважды?

резюме: переписать полностью с нуля. никуда не годится.
Автор: israel_rider
Дата сообщения: 02.07.2009 12:00
zerkms! Огромный сенкс за помощь и поддержку! Переписываю! Но, плиз, несколько вопросов.
«3. лапша %» - Не понял вообще, о чём ты.
«7. имена всех переменных поменять на релевантные и переведённые на английский язык» Дело в том, что мне так очень удобно. Когда я даю переменным левые имена, я точно знаю, что они у меня не повторяться. У меня уже и так голова пухнет, каждый раз, когда приходиться придумывать имя для переменной. А не называл ли я так уже что нибудь. И не только переменные. Каждый раз, когда придумываешь имя класса CSS, та же проблема.
«4. тип файла нужно брать не из mime, а из того, что возвращает getimagesize» Вообще беда . Пишу
$prvrkfaila = getimagesize($_FILES['imyfaila']['tmp_name']);
echo image_type_to_mime_type($prvrkfaila);
А он у меня пишет «image/gif». И это то при том, что я загружаю реальную фотографию с расширением «jpg»!!!!


Добавлено:
Вот, переписал. То, что понял из твоих замечаний, изменил.
<?php
if (!isset($_POST['fotobook'])) header("Location:book.php");      // Если юзер нажал кнопку "Загрузка файлов" что бы загрузить файл
if ($_FILES["imyfaila"]["size"] > 1024*2*1024) { // Проверяем размер
    echo "<h1 STYLE='color:red;'>Размер файла превышает 2 мегабайта.</h1><h2><a href=\"#\" onclick='history.back()'>Вернуться к отправке</а></h2>";
    exit();
}    
$prvrkimya = trim($_FILES["imyfaila"]["name"]); // Убираем пробелы с начала и конца оригинального имени фотки
$prvrkimya = substr($prvrkimya, -15); // Обрезаем оригинальное имя до 15-и знаков с конца
$asdfg = pathinfo($prvrkimya);
if ($asdfg['extension'] !== 'jpg') { // Проверяем расширение оригинального имени
    echo "<h1 STYLE='color:red;'>Это походу не фотка ни хрена... </h1><h2><a href=# onClick='history.back()'>Вернуться к отправке</а></h2>";
    exit();
}
$prvrkfaila = getimagesize($_FILES['imyfaila']['tmp_name']);//Проверяем, не (removed) ли с расширением подделов "Content-Type"
if ($prvrkfaila['mime'] != 'image/jpeg') {
    echo "<h1 style='color:red;'>Чёто не тое... </h1><h2><a href=\"#\" onclick='history.back()'>Вернуться к отправке</a></h2>";
echo '<br/><br/><br/>'.$prvrkfaila['mime'];
exit();    
}
move_uploaded_file($_FILES['imyfaila']['tmp_name'], "knigajiz/vremenni.jpg"); // Если фотка всё выдержала, помещаем её в папку под временным именем
?>
Автор: zerkms
Дата сообщения: 02.07.2009 12:24

Цитата:
А он у меня пишет «image/gif». И это то при том, что я загружаю реальную фотографию с расширением «jpg»!!!!

расширение ничего не значит. открой файл и посмотри сигнатуру в начале:
&#255;&#216;&#255;&#224;&#12544;JFIF - jpg
GIF89 - gif
Посмотри как работать с getimagesize(), ты не совсем понимаешь.

далее - смотри в документацию по move_uploaded_file() - посмотри, что оно используется в паре с if() обычно.

if ($asdfg['extension'] !== 'jpg') { // Проверяем расширение оригинального имени
зачем тебе проверять расширение?????? getimagesize() возвращает тебе и так тип картинки.

лапша - это значит адская смесь кода и отображения. это значит неподдерживаемый и нечитаемый код.

$prvrkfaila = getimagesize($_FILES['imyfaila']['tmp_name']);//Проверяем, не (removed) ли с расширением подделов "Content-Type"
if ($prvrkfaila['mime'] != 'image/jpeg') {
этот код работать не может. getimagesize() возвращает числовой массив. ассоциативного ключа mime в нём быть не должно.
Автор: israel_rider
Дата сообщения: 02.07.2009 12:41
zerkms, я думаю над тем, что ты сказал, но вообще то....
Вот здесь, http://il.php.net/manual/en/function.getimagesize.php , написано вот это, копирую целиком:
"

Index 2 is one of the IMAGETYPE_XXX constants indicating the type of the image.

Index 3 is a text string with the correct height="yyy" width="xxx" string that can be used directly in an IMG tag.

mime is the correspondant MIME type of the image. This information can be used to deliver images with correct the HTTP Content-type header:

Example #1 getimagesize() and MIME types

<?php
$size = getimagesize($filename);
$fp = fopen($filename, "rb");
if ($size && $fp) {
header("Content-type: {$size['mime']}");
fpassthru($fp);
exit;
} else {
// error
}
?>
"
Получается, getimagesize() возвращает не числовой массив. а смешанный, и один из его ключей как раз "['mime'].

Добавлено:
Вообще то, при написании кода, я руководствовался вот этой http://habrahabr.ru/blogs/php/44610/ статьёй. Там, в часности, автор доказывает, что всегда имеет смысл проверять расширение загружаемого файла, что бы там не было, ну например, "РНР".
Автор: israel_rider
Дата сообщения: 02.07.2009 23:25
Попрос номер раз.
zerkms говорит, что это:
$prvrkfaila = getimagesize($_FILES['imyfaila']['tmp_name']); //Проверяем, не накололи ли с расширением, подделов "Content-Type"
if ($prvrkfaila['mime'] != 'image/jpeg') {
echo "<h1 style='color:red;'>Чёто не тое... </h1><h2><a href=\"#\" onclick='history.back()'>Вернуться к отправке</a></h2>";
echo '<br/><br/><br/>'.$prvrkfaila['mime'];
exit();
}
Работать не может, поскольку getimagesize(); возвращает числовой массив, а не ассоциативный. Я же прочитал совсем другое, мануал РНР процитирован выше.
Вопрос, как же оно на самом деле? И кста…. Хоть мой код и обозвали «лапшой», но проверяю я его всегда очень тщательно. Всё, что я написал работает.


Добавлено:
Вопрос номер два
«отрубить php в дире, куда заливается картинка»
Если уважаемый Черри имеет в виду не допустить, что бы фотка записалась с расширением «РНР», то я в принципе, после того как меняю размер залитой фотографии, копирую её на её постоянное место жительства вообще под другим именем. И конечно же расширение в этом имени стандартное, «фотографическое».
Вопрос, это имелось в виду?



Добавлено:
Вопрос номер 3

Цитата:
Посмотри как работать с getimagesize(), ты не совсем понимаешь.

Родной мануал РНР по фукции getimagesize() я изучил досканально. Прочитал его вдоль и поперёк. Соблаговолите указать конкретно, где именно в данном вопросе я ошибаюсь?
Автор: Cheery
Дата сообщения: 02.07.2009 23:46
israel_rider

Цитата:
Работать не может, поскольку getimagesize(); возвращает числовой массив, а не ассоциативный. Я же прочитал совсем другое, мануал РНР процитирован выше.


Цитата:
<?php
print_r(getimagesize("image.png"));
?>

ответ

Цитата:
Array ( [0] => 259 [1] => 32 [2] => 3 [3] => width="259" height="32" [bits] => 8 [mime] => image/png )


Цитата:
Вопрос, это имелось в виду?

имелось в виду - для безопасности. ресайз приводит к потере качества, без него для безопасности можно и отрубить
Автор: israel_rider
Дата сообщения: 03.07.2009 00:00
Так, понял. По поводу getimagesize() вопрос закрыт. Черри супер наглядно продемонстрировал, что getimagesize() возвращает смешанный массив. Я всё сделал правильно.
Далее, мне без ресайза не обойтись. Пользователи заливают мне фотки любых размеров, я же вывожу их им в двух стандартных размерах – большом и «провью». С этим я тоже успокоился. И, кста. В той статье с Хабрахабра, ссылку на которую я привёл, автор доказывает, что обрубить расширение РНР тоже не панацея. При определённых настройках сервера он может обрабатывать графические файлы как файлы РНР. И тогда, даже без расширения РНР скрытый в файле вредоносный код начнёт работать. Получается, единственная панацея – ресайз.
Автор: Cheery
Дата сообщения: 03.07.2009 00:17
israel_rider

Цитата:
При определённых настройках сервера он может обрабатывать графические файлы как файлы РНР

очень и очень редко. почти никогда, а уже если так настроил админ - его проблемы
CGI в принципе запрещать надо.
Автор: israel_rider
Дата сообщения: 03.07.2009 00:18
Ещё вопросик, плиз. Можно регулярное выраженице готовенькое? А то, если я ещё с регулярными выражениями начну сейчас запариваться, у меня точно крыша отъедет. Нужно проверять данные, вводимые пользователем. Имя, адрес…. По идее, должны быть русские буквы, латиница…. И всё? Вот так можно проверять?
if (preg_match("/[^(\w)|(\@)|(\.)]/", $imel)) $imel='Ошибка';
Хотя, всё равно понять не могу. У меня пользователи вводят большие куски текста через текстареа. И эти большие куски текста сказано проверять так:
$malavabg=htmlspecialchars($malavabg, ENT_QUOTES);
Вопрос. Если текстарея я всё равно не проверяю при помощи регулярных выражения, какой смысл проверять при помощи регулярных выражений что то другое? Злоумышленник, то, что он захочет ввести введёт через текстареа. Так тогда уж всё можно проверять при помощи только htmlspecialchars()? Выходит, если я хоть гдето не проверяю при помощи регулярных выражений, я могу тогда в данном коде не использовать их вообще?

Автор: Cheery
Дата сообщения: 03.07.2009 00:23
israel_rider

Цитата:
Можно регулярное выраженице готовенькое?

PHP: Регулярные выражения (RegExp, Regular, eregi, preg)


Цитата:
И эти большие куски текста сказано проверять так:

это - не проверка. а всего лишь замена кавычек на их html entities


Цитата:
Вопрос. Если текстарея я всё равно не проверяю при помощи регулярных выражения, какой смысл проверять при помощи регулярных выражений что то другое? Злоумышленник, то, что он захочет ввести введёт через текстареа. Так тогда уж всё можно проверять при помощи только htmlspecialchars()? Выходит, если я хоть гдето не проверяю при помощи регулярных выражений, я могу тогда в данном коде не использовать их вообще?

проверяете что??? с этим определитесь сначала. зачем что то писать, если не понимаете от чего защищает? при введенных данных вам нужно
1) защититься от ввода html тегов (XSS)
2) защита от SQL injection в SQL
вот и все.. первое - htmlentities или htmlspecialchars
второе - mysql_real_escape_string
Автор: israel_rider
Дата сообщения: 03.07.2009 00:31
Про mysql_real_escape_string вообще первый раз слышу! Всё понял, сейчас буду читать про неё. Огромный преогромный сенкс!!!!!!!!!!!!!!!!!!!!!!! Хоть какую то ясность обрёл. Уж если не сейфовый замок, то хоть как то двери и окна прикрыл.
Автор: israel_rider
Дата сообщения: 04.07.2009 12:16
Уважаемые Cheery и другие проффессионалы. А как же мне защититься от XSS-атаки, если злоумышленник ввдодит мне в поле формы скрипт, написанный в кодировке UTF-7? Функция htmlspecialchars() в этим случае мне не поможет.

Добавлено:
Вот, сделав вывод из того, что сказал Cheery, написал функцию для проверки данных, вводимых пользователем в поля формы.
<?php
function antuvzlomsql($fromfrm)
{
    if (!is_numeric($fromfrm)) { // Если переменная - число, то экранировать её не нужно, если нет - экранируем
 $fromfrm = htmlspecialchars($fromfrm, ENT_QUOTES);
         $fromfrm = mysql_real_escape_string($fromfrm);
    }
return $fromfrm;
}
?>
Вопрос. Достаточно ли надёжна такая проверка, если после проверки эти данные предполагается заносить в базу данных, а потом выводить на страницах сайта?
Автор: Cheery
Дата сообщения: 04.07.2009 19:35
israel_rider
а если массив?
ну это смотря что посылаться для проверки будет.

Цитата:
А как же мне защититься от XSS-атаки, если злоумышленник ввдодит мне в поле формы скрипт, написанный в кодировке UTF-7? Функция htmlspecialchars() в этим случае мне не поможет

где об этом написано? делайте сайт в UTF-8 и работайте с этой кодировкой
Автор: israel_rider
Дата сообщения: 04.07.2009 19:45

Цитата:
где об этом написано?
Написано в этой http://www.captcha.ru/articles/antihack/ статье, в параграфе «XSS и UTF-7». У меня сайт естественно в UTF-8, но в статье написано, что браузер, встретив символы UTF-7, может переключиться на неё , и выполнить вредоносный код.
Автор: Cheery
Дата сообщения: 04.07.2009 19:48
israel_rider

Цитата:
что браузер, встретив символы UTF-7, может переключиться на неё

с чего бы, если это будет в каком то куске страницы?
если, конечно, не разрешаете вставлять что то в head область страницы
но ведь вы же выдаете content-type с кодировкой? ему предпочтение и будет отдаваться
Автор: israel_rider
Дата сообщения: 04.07.2009 19:50
Cheery, прошу прощение за непонятливость. Что значит
Цитата:
а если массив?
Как пользователь может ввести мне через поле формы МАССИВ??!!! И зачем? Как введение массива позволит хакеру взломать сайт? И ни чего не могу понять из данного высказывания, и ни где ни чего подобного не читал!!!!
Автор: Cheery
Дата сообщения: 04.07.2009 19:55
israel_rider
я к тому, что если у вас данные в конце концов в массиве, который вы и хотите обезопасить, не будете же для каждого элемента вызывать эту функцию.

Цитата:
И зачем? Как введение массива позволит хакеру взломать сайт?

речь не о введении массива. просто подумайте.. когда много данных из формы и используется написанная вами функция.. вы все эти данные будете передавать как аргументы функции или же запихнете их в массив?
Автор: israel_rider
Дата сообщения: 04.07.2009 20:17
Да. Теперь понял. Я задумывался об этом, у меня на одной страничке было действительно много данных из формы. И в таком случае я выполню проверку так. Выполняю итерацию по массиву POST при помощи функции foreach, и во время итерации передаю каждое значение из массива РОST этой функции для проверки. А вообще, конечно, думать надо, экспериментировать. Точно мне и не сказать, с ходу.

Добавлено:
По поводу кодировки. Проверил сейчас ещё раз при помощи «Display ieHTTPHeaders». Мой сервер выдаёт мне странички с уже прописанным Content-Type: text/html; charset=UTF-8 в заголовках. Поэтому то я в мета тегах Content-Type и не пишу, это неправильно, раз сервер уже Content-Type в загаловках прописал. Так меня учили, по крайне мере.
Вопрос.
Значит ли это, что Content-Type уже чётко определён, и браузер на UTF-7 не переключится?
Автор: Cheery
Дата сообщения: 04.07.2009 20:28
israel_rider

Цитата:
Значит ли это, что Content-Type уже чётко определён, и браузер на UTF-7 не переключится?

попробуйте - узнаете.
не должен.
Автор: israel_rider
Дата сообщения: 04.07.2009 20:31

Цитата:
если, конечно, не разрешаете вставлять что то в head область страницы
Ну нет. Уж туда я, слава богу, ни чего от пользователей не пихаю. Только мною определённые данные, динамические или статические.

Добавлено:
Так. Со всем этим пока какую то ясность обрёл. И душевный покой. Временно. Огромный сенкс.
Автор: israel_rider
Дата сообщения: 05.07.2009 08:00
Cheery, вчера мы с Вами говорили о том, что конструируя функцию проверки данных, введённых пользователем через HTML форму, неплохо было бы предусмотреть возможность автоматической проверки всего массива данных, в том случае, если этих данных так много, что непроизводительно было бы вручную вызывать функцию для каждого значения. С целью тренировки и совершенствования навыков программирования я написал такую функцию. Вот она:
Код:
include ("connect.php"); // Cначала, естественно, подключаемся к БД, поскольку нам придётся вызывать функцию mysql_real_escape_string() .
function checking($arr) { // Это и есть функция, которая проверяет данные, введённые пользователем, находящиеся в массиве $_POST
     foreach ($arr as $key => $value) {
            if (!is_numeric($value)) { // Если переменная - число, то экранировать её не нужно, если нет - экранируем
                $value = htmlspecialchars($value, ENT_QUOTES);
             $value = mysql_real_escape_string($value);
     }
            $kluchi[] = $key;
            $znacheniya[] = $value;
}
        $result = array_combine($kluchi, $znacheniya);
        return $result;
    }
    $checked = checking($_POST); //Вот теперь у нас уже есть массив с проверенными данными, которые можно помещать в таблицу БД, а //так же выводить на страницах сайта.
    print_r($checked); //Посмотрим на результаты нашего нелёгкого труда и затащимся
Автор: Ternik
Дата сообщения: 05.07.2009 19:03
а если в $POST занести массив? Например:

Код:
<input name="s[1]"" value="0">
<input name="s[2]"" value="1">
Автор: israel_rider
Дата сообщения: 05.07.2009 20:27

Цитата:
а если в $POST занести массив? Например:
Вообще ни чего не понял. $_POST - это же и есть массив! В нём находятся данные, введённые пользователем через HTML форму, я об этом написал. Вот их то я и проверяю при помощи своей фукции.

Добавлено:
Что такое "функции GPC" вообще ни разу не слышал. И в Гугле ни чего не нашёл.
Автор: Ternik
Дата сообщения: 12.07.2009 02:35

Цитата:
Что такое "функции GPC" вообще ни разу не слышал. И в Гугле ни чего не нашёл.

GET POST COOKIE

Добавлено:

Цитата:
$_POST - это же и есть массив!

а это массив массивов

Добавлено:
mass cookie

Добавлено:
подсекайте заросы к MySQL!
Автор: israel_rider
Дата сообщения: 12.07.2009 06:50
Ternik , пытался понять твои намёки..... GET POST COOKIE содержаться в массиве $_REQUEST . Стал смотреть про $_REQUEST , наткнулся на "Функции фильтрации данных", http://il2.php.net/manual/ru/book.filter.php. Всё это очень интересно конечно.... Может смогу вернуться к этому позже.... Сейчас нет ни сил не времени. Надо срочно к сайту Аякс прикручивать...
Автор: israel_rider
Дата сообщения: 16.09.2009 16:30
Cheery, на сайте клиента я обнаружил очень пугающий файл. Файл явно не с сайта. Как он появился в этой директории непонятно. Формат HTML, весит порядка 100КВ. Я его, естественно попробовал открыть в редакторе, но помоему, вся информация в нём зашифрована. Нельзя ли послать Вам этот файл, что бы Вы на него посмотрели?

Страницы: 1234567

Предыдущая тема: WAP+PHP и русские буквы


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.