Читал мануал по пхп с комментариями, наткнулся на один пост, который дал повод для размышления. Автор использует этот скрипт для подгонки всех подгружаемых изображений: PHP: <?php class picture { var $save_dir; //where file will be saved var $filename="spacer.gif"; //default file name initially var $error_message=""; //string to be output if neccesary var $width; //height of final image var $height; //width of final image function picture($save_directory, $file_array, $max_width, $max_height) { $this->save_dir = $save_directory; $this->width = $max_width; $this->height = $max_height; //--change filename to time - make it unique $temp_filename = $file_array['name']; $ext = explode('.',$temp_filename); $ext = $ext[count($ext)-1]; $temp_filename = time().".".$ext; //--check that it's a jpeg or gif if (preg_match('/^(gif|jpe?g)$/',$ext)) { // resize in proportion list($width_orig, $height_orig) = getimagesize($file_array['tmp_name']); if ($this->width && ($width_orig < $height_orig)) { $this->width = ($this->height / $height_orig) * $width_orig; } else { $this->height = ($this->width / $width_orig) * $height_orig; } $image_p = imagecreatetruecolor($this->width, $this->height); //handle gifs and jpegs separately if($ext=='gif'){ $image = imagecreatefromgif($file_array['tmp_name']); imagecopyresampled($image_p, $image, 0, 0, 0, 0, $this->width, $this->height, $width_orig, $height_orig); imagegif($image_p, $this->save_dir.$temp_filename, 80); } else { $image = imagecreatefromjpeg($file_array['tmp_name']); imagecopyresampled($image_p, $image, 0, 0, 0, 0, $this->width, $this->height, $width_orig, $height_orig); imagejpeg($image_p, $this->save_dir.$temp_filename, 80); } imagedestroy($image_p); imagedestroy($image); $this->filename=$temp_filename; }else{ $this->error_message.="<br> file is not a jpeg or gif picture <br>"; } } } Но чем не способ фильтровать полученные файлы? Проблема только одна: для работы требуется поддержка GD в пхп, но в данный момент на большинстве хостингов она есть. Вот набросанный за пару минут класс для фильтрации картинок: PHP: <?php /** * Класс для проверки изображений * */ class SecureImage { /** * Картинка * @var resource */ private $img = null; /** * Данные о картинке * @var array */ private $data = null; /** * Тип изображения * @var string */ private $type = null; /** * Конструктор класса * * @param string $s_patch Папка для сохранения картинки */ public function __construct($image_data) { $this->data = $image_data; } /** * Деструктор класса */ public function __destruct() { if ($this->img) { imagedestroy($this->img); // освобождаем память } } /** * Проверка изображения * * @param array $image Массив с данными о загруженом файле из $_FILES * @return boolean Результат проверки */ public function check() { $ext = explode('.',$this->data['name']); $ext = trim(strtolower($ext[count($ext)-1])); switch ($ext) { case 'gif': $this->img = @imagecreatefromgif($image['tmp_name']); $this->type = 'gif'; break; case 'jpeg': case 'jpg': $this->img = @imagecreatefromjpeg($image['tmp_name']); $this->type = 'jpg'; break; case 'png': $this->img = @imagecreatefrompng($image['tmp_name']); $this->type = 'png'; break; } if ($this->img) { return true; // и правда, картинка } else { return false;// шелл батькович } } /** * Созранение изображения * * @param string $patch Путь для сохранения * @return boolean Результат сохранения */ public function save($patch) { if (!$this->img) { return false; } switch ($this->type) { case 'gif': return imagegif($this->img, $patch); // на случай, если прав на запись в указанном месте нет break; case 'jpg': return imagejpeg($this->img, $patch); break; case 'png': return imagepng($this->img, $patch); break; default: return false; break; } } /** * Возвращает расширение для картинки */ public function getExtension() { return $this->type; } } Вот пример его использования: PHP: $img = new SecureImage($_FILES['some_image']); if ($img->check()) { // и правда, картинка - продолжаем. $img->save('/path/to/images/my_image.' . $img->getExtension()); } else { // shell, как он есть, или ошибка в картинке } Недостаток в том, что поддерживаются только gif, jpeg и png. Хотя аватарок в psd я нигде и не видел... В общем, хочу узнать ваше мнение
Как тебе отобразаятся изображения в .psd формате? Бразуер предлагает скачать файл, но он никак не отобразится как картинка.. .psd файл вроде - исходник изображения в фотошопе...
ждем обещаного в ирц мегатру кода by Z ps: Isis, было бы желание, а написать модуль для отображения какой либо графики не проблема
Гема в irc доказывал, что проверка содержимого не состоятельна, т.к. благодаря специфике форматов изображений можно вставить нужный код в различные коментарии, etc в тело картинки. Предложенный мною метод переноса "изображений" из временной папки хорош тем, что благодаря особенности GD - эта библиотека не работает с мета-данными файлов, а использует только ту информацию, которая используется при построении растра. И сохраняет GD, соответственно, только графическую информацию, т.е. вставки шеллкода в различных полях идут лесом. Вот этим кодом преобразовал файл с встроенным куда только можно кодом <?php phpinfo(); ?> (image.jpg) PHP: $im = imagecreatefromjpeg('image.jpg'); imagejpeg($im, 'newimage.jpg'); После сохранения были вырезаны все мета данные, и размер избражения изменился: image.jpg: 3.75 кб newimage.jpg: 2.33 кб На выходе имеем "чистую" картинку, что и требовалось.
да собственно никто етого делать и не заставляет. просто пример как можно поиздевается с ГД. сели не уверен в отсутствии локального инклуда в скриптах, то можно перестраховаться таким способом. хотя в етом случае можно разводить демагогию по поводу "ты хyевый программер если предполагаешь саму возможность ошибки". в крайнем случае, всегда можно оправдать подобные телодвижения довольно неслабым уменьшением размера полученной картинки =) кстати, если не ошибаюсь на nnm используется что-то подобное.
Я не знал что библиотека gd режет все лишнее поэтому вот окончательный код имхо.Правда если мы имеем дело с залитием например видео то wmv не прописан в майм тайпах апача по умолчанию и поэтому файл shell.php.wmv будет интерпретироваться именно как php , так что проверка по расширению имхо наилучшая. http://underwater.itdefence.ru/safe_upload.txt
А зачем такие сложности? Ну допустим у тебя шелл внутри картинки. И что с того? Я еще понимаю, можно что из-за кривых bb-кодов(человеческий фактор) допустить дыру, но вот из-за инклюдов....
Нер я тоже не понимаю как люди допускают ошибки типа инклуда но ведь даже очень хорошие программисты ошибались.х3
Я на своих проектах юзаю следующий алгоритм 1 Проверка расширения 2 Проверка Mime типа 3 Проверка типа вообще (через exif_imagetype) 4 Проба ширины и высоты - имеют ли числовые значения Далее можно пере-рендерить картинку как уже написал Helios: $im = imagecreatefromjpeg('image.jpg'); imagejpeg($im, 'newimage.jpg', 100); Если рендерить и менять ширину/высоту по какой-то причине нельзя, то можно проверсти вот такую проверочку содержимого картинки <meta http-equiv="content-type" content="text/html; charset=windows-1251"> <?php $result_of_scan=""; $uploaded_img="resized.jpg"; $fh=fopen($uploaded_img, 'r'); $contents_of_uploaded_img=fread($fh, filesize($uploaded_img)); fclose($fh); $list_of_potential_xss=array('javascript', 'vbscript', 'expression', 'applet', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base', 'onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload', 'input', 'form', 'post','input', 'echo', 'background', 'alert', 'img src', 'table', 'Content-Type', 'charset', 'http-equiv', 'meta', 'body', 'document', 'style', 'cookie', 'false', 'true', 'delete', 'UTF-7', 'UTF-8', '.html', '.dhtml'); for($x = 0; $x < count($list_of_potential_xss); $x++) { preg_match("/".$list_of_potential_xss[$x]."/", $contents_of_uploaded_img, $matches); if(count($matches) > 0) { $result_of_scan="true"; echo "$list_of_potential_xss[$x] - присутсвует<br><br>"; } else { echo "$list_of_potential_xss[$x] - отсутсвует<br><br>"; } } if ($result_of_scan==="true") { echo ("<b><h1>XSS есть"); } else { echo ("<b><h1>Все чисто"); } ?>
1. Эта проверка идёт лесом. пример тому. <IMG DYNSRC="javas cript:al ert('XSS')"> 2. вроде разговор о шеллах, а чёт похоже на защиту от XSS, если ты имел ввиду XSS то читай первый пост. А если ты говорил про пхп шелл то за GZIP'еный шелл склееный с картинкой ты тоже не спалишь этим скриптом. Так что либо дорабатывай, либо забудь об этой защите
Эта проверка чисто для экспериментов (хз каких)) В любом случае проще пере-рендерить картинку и весь побочный код идет лесом.
Как я уже говорил, Gd считывает и сохраняет только графические данные, используемые для построения растра, т.е. все техничесие поля остаются неудел.