Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #61 (permalink)  
Старый 17.02.2018, 21:37
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,791

kupidon,
$file = 'https://www.google.ru/images/srpr/logo11w.png';
// Добавляю хэш к имени файла
$file_name = md5(microtime(true).rand(0,999999)).'_'.basename('https://www.google.ru/images/srpr/logo11w.png');
$file=file_get_contents($file);
$file_path='my_folder'.$file_name;
if(empty($file))
	throw new \Exception('Could not read remote file');
	
if(file_put_contents($file_path,$file)<=0)
	throw new \Exception('Could not save remote file');

// я бы проверял не заголовки ответа удаленного сервера на запроса изображения, 
// а сам полученный файл, на то является ли он изображением или нет
Ответить с цитированием
  #62 (permalink)  
Старый 17.02.2018, 22:47
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

Сообщение от kupidon
/denwer/errors/phperror_js.php
Денвер в утиль, он давно умер, скачивайте Open Serever. Это такой же компактный не требующий инсталляции и работающий с чего угодно как и Денвер локальный сервер, но с гораздо большими возможностями и более удобный. Проект живой и постоянно обновляется как по мере выхода новых версий компонентов, так и в плане новых возможностей.

Сообщение от kupidon
$mime = array('image/png', 'image/jpeg'); //переделал строку с вашим кодом, а то он ругался на кв ковычки
Квадратных кавычек нет. Ругается потому, что вы используете версию РНР ниже 5.4, в которых нельзя объявить массив литерально [], а только как array(). Вы должны использовать ту версию языка, которая доступна на реальном сервере. И если доступны версии 5.4 и выше, то ориентируйтесь на них, в них больше возможностей, что позволяет писать код более компактным, ну и конечно же, это устранение "болезней" предыдущих версий.

Поэтому если я далее пишу код, то ориентируюсь на версию не ниже 5.5, учитывайте это.

Сообщение от kupidon
НО поскольку для меня это темный лес, и все функции для меня новые.
Это не страшно, достаточно заглянуть в руководство по языку (это должно быть настольной книгой, библией на ночь, которую можно скачать на официальном сайте в формате CHM), и в темном лесе появятся проблески света.

Сказанное выше, это рекомендации, и это я советую сделать. А то, что далее написано, это вы должны делать и не потому, что я советую, а вы уважаете. Все что ниже, вы обязаны делать исходя из требований к безопасности кода.

**********

Возможно и много писанины получится, пока есть время написать можно (чем дольше читать будут и переваривать, тем больше у меня времени будет ). Повествование в томах, дабы не напороться на ограничения.

Война и мир. Ремейк. Том 62

Ужастики

Также я загружаю фото из карточки УЖЕ созданного товара, а следовательно не надо проверять есть он в БД или нет. Он есть 100%.

Второе предложение можно принять за постулат, а вот первое будет постулатом только пока выборка из базы живет на сервере. Как только результат выборки отдали клиенту, можно смело сказать, что она уже не принадлежит базе потому, что нет такой же 100-процентной гарантии, что она вернется на сервер в том же виде.

Существует опасный вид атаки называемый "человек посередине" (Man in the middle, MITM), которой подвержены и безопасные соединения, а обычный http тем более. Вы отдали клиенту "У нас все замечательно!", а клиент может получить "Кошка сдохла." и вернет вам "Примите наши соболезнования." Кроме этого в сети шарятся кучи ботов сканирующие страницы с формами и отсылающие их копии серверу жертве.

Если не учитывать всех "сетевых насекомых", принимать на веру как есть, то такая вера может закончится большим разочарованием. Например, в вашем случае в таблице описывающей файлы товаров появятся "бесхозные" записи, а в каталог будут залиты бесполезные картинки.

Дихлофос

Защита, это вопрос серьезный, широкий, понимание и знания будут накапливаться, нужно только обязательно интересоваться этими вопросами. Но уже в самом начале практики написания кода нужно выполнять элементарные действия:

- сервер отдавая данные клиенту не должен допустить на нем XSS атаки, пропуская вывод данных полученных извне через htmlspecialchars()
- не использовать в именах полей формы имена SQL таблиц, а если используются, то только их часть после префикса
- данные поступающие на сервер извне подлежат обязательной проверке/фильтрации
- блокировать вывод ошибок и предупреждений на страницах на удаленном сервере

Как пример, а не обязательное требование использовать.

Надежный пароль 123456789, это уже анекдот, но тем не менее такое есть и не в единственном случае. Сюда же можно отнести и именование полей форм: name, first_name, last_name, phone, email, login, password, ... или вариации этого. Боты такие формы любят, что и для чего ясно, и китайца "арендовать" не нужно для снятия слепка с формы.

Как можно продихлофосить. Например, все имена формы содержат первичный ключ, который есть хеш случайного значения, который формируется сервером и запоминается на нем. Вторичные ключи, это индексы реальных имен, которые могут быть связаны и с именами полей SQL таблицы, и прочими другими данными, и которые знает только сервер. То есть имена полей будут выглядеть так:

name="4a0d42e025eb49edf7f292be67c1099f[5]"
name="4a0d42e025eb49edf7f292be67c1099f[1]"
name="4a0d42e025eb49edf7f292be67c1099f[3]"
....
name="4a0d42e025eb49edf7f292be67c1099f[9]"

При каждом запросе формы первичный ключ меняется. Ключ живет только на время сессии, а также удаляется после приема формы. То есть, нельзя будет отправить вторично эту форму, север ее просто не примет, так как ключа ее на сервере не будет.

Использование иконок для полей вместо текстовых меток, формирование формы клиентским сценарием еще более осложняет жизнь боту.

Рекогносцировка

Хорошим тоном является оповещение клиента о предпочтениях сервера - чего он хочет получить от клиента. А проверка ввода в поля формы соответствию ожидаемому не являясь средством защиты для сервера и служащая для предотвращения случайных ошибок пользователя, тем не менее дает серверу карт-бланш. Сервер зная о том, что клиент им информирован по всем полям, клиент имеет предоставленный ему сервис предотвращающий ошибки, обнаружив первое же несоответствие в полученных данных может законно завершить работу, не разбираясь далее.

В современном HTML информирование и проверку можно возложить на браузер без всяких затрат на написание кода. Но в форме загружающей файлы для таких полей нативной проверки нет. Более того, если сервер не сообщит клиенту параметров по загрузке, то и пенять не на кого. Клиент должен быть извещен о типах файлов, которые примет сервер. Эти типы нужно перечислить в атрибуте accept поля file. Умные браузеры в диалоге выбора файлов будут отображать файлы только указанных типов. Клиенту также передается максимальный размер файла, который можно загрузить, общее количество файлов для загрузки за один раз, и максимальный размер данных, который можно передать методом POST. Эти данные сервер должен получить из настроек сервера, передав их клиенту.

Если файлы, это графика и предполагается ее обработка на сервере, то клиенту должно быть передан размер памяти доступный под такую обработку.

При выборе файлов, клиентский сценарий должен проверять выбранное на соответствие типу, размеру, количеству и соответствие общего размера выбранного разрешенному для загрузки. А если предполагается работа с графикой, то получать разрешение выбранных файлов, рассчитывать объем памяти под них требуемый, чтобы он не был больше допустимого сервером. Либо просчитав возможности сервера, не разрешать к загрузке графику выше определенного разрешения.

********

Если эти замечания вам известны, а тем более выполняются в ваших формах, это хорошо, то, что зря я по клавишам стучал, не страшно. Но если из этого что-то упущено или не сделано из-за принципа "нужно проще", то смысла в терзаниях "как написать код загружающий файл" нет, так как то, что выше, это обязательная преамбула к коду.

Последний раз редактировалось laimas, 18.02.2018 в 00:41.
Ответить с цитированием
  #63 (permalink)  
Старый 17.02.2018, 23:47
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

Том 63

Бастион

Сервер обязан проверять данные соответствию ожидаемых. Вы не разобрались с кодом, который я писал, а вам еще и советуют разное, и вы путаясь делаете то, что не следует.

Вы получаете ссылки на сетевые файлы, но не видно чтобы вы учитывали возможные случайные ошибки пользователя, и самые частые, это лишние пробелы по краям. Либо вы проверяя каждое значение формы в цикле (во время фильтрации), удаляете их, любо удалите их сразу у всех значений массива, если над данными производятся групповые операции:

if($_POST) {
    array_walk_recursive($_POST, function(&$v) {
        $v = trim(stripslashes($v));
    });
}


В вашем коде вы допускаете опасные ошибки. Не проверив наличие файла по сетевому пути (проверять его наличие загрузкой по факту, это расточительно), используя имя файла источника, опять таки не проверив что это за файл, загружаете его в каталог:

$file_name = basename('https://www.google.ru/images/srpr/logo11w.png');
file_put_contents('my_folder'.$file_name, file_get_contents($file));

Это предпосылка к тому, что на ваш сервер через эту дыру зальют исполняемый файл. Если каталог не защищен от запуска в нем исполняемых файлов, то его сразу же и запустят, и ...

Если, допустим, будут разрешены переходы при получении сетевых файлов, то придется анализировать заголовок Location, а к примеру я его могу и как location написать. В общем ранее написанный код лучше немного дополнить

//с учетом, что возможные крайние пробелы удалены в данных
if($url = //массив ссылок на сетевые файлы не пуст, empty тут как козе баян
    array_diff( //удалить из массива
        filter_var_array( //проверить массив данных
            $_POST['file'], 
            FILTER_VALIDATE_URL //фильтом проверки URL
        ), 
        [false]) //элементы не прошедшие фильтрацию
    ) {
    
    foreach($url as $a) {  
        $hdr = array_change_key_case(get_headers($a, 1)); //запросить информацию о файле, вернув заголовки как ключи в нижнем регистре 
        if(strpos($hdr[0], '200')) { //файл существует
            if(in_array($hdr['content-type'], $mime) && $hdr['content-length'] <= $size) $upl[] = $a; //если разрешенный тип и размер, добавить в загрузку  
        }
    }
     
    foreach($upl as $url) { //есть сетевые файлы для загрузки 
        if($f = @file_get_contents($url)) { //считываем файл
            //никаких сохранений в каталог
            //если использовать getimagesize для проверки разрешения, то только во временный файл
            //но можно получить ширину/высоту и без этого, просто распаковав эти данные из заголовка файла  
            //если тип, объем памяти Ок, отдаем на обработку
            if(processingIMG($f)) echo 'Error';   
        }
    }
}

function processingIMG($f, $name) {
    $end = 0;
    //то что предыдущие проверки типа возвращают ОК, еще не значит, что файл есть графика
    //здесь открывается GD ресурс из строки
    //если файл не графика, значит ресурс не будет создан  
    if(!$im = @imagecreatefromstring($f)) {
        $end = 1; //файл не является изображением
        goto out;
    }
    //далее операции над файлом
    //сохранение, под сгенерированным именем, по указанному пути, с одним типом, чай не галерея искусств
    //с определенным установками качеством через константу QUALITY
    imagejpeg($im, $name, QUALITY);
    out:
    @imagedestroy($im);
    return $end;
}

Последний раз редактировалось laimas, 18.02.2018 в 19:14.
Ответить с цитированием
  #64 (permalink)  
Старый 18.02.2018, 01:27
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

Том 64

После битвы

Можете представить, что вы беседуете с роботом "за жизнь"? Нет, беседовать можно, конечно, но вот вряд ли он вас поймет. Аналогично - сервер зная, что клиент оповещен, а значит, если в пришедшем ошибки, которые явно есть результат обхода проверки ввода или вообще роботом прислано, нужно ли серверу вести с роботом диалог?

Если предполагается диалог клиент сервер, в случае, если на клиенте нет проверки ввода, тогда да, возвращаем клиенту ошибки. Иначе exit, сообщение "Could not read remote file" роботу как мертвому припарка, а желающему вас прощупать не стоит сообщать подробностей. А на локальном сервере, в режиме отладки, нужно выводить даже предупреждения, безобидность, на первый взгляд, некоторых, может быть причиной уже ошибок далее в коде. Режим отладки можно включать и на удаленном сервере если пользователь имеет права "видеть их". Возникают и на удаленном сервере ошибки, причиной которых могут быть конфигурации или иные особенности сервера, которые на локальном сервере не отследить.

Процессы над графикой могут порождать ошибки, хотя если заранее определено разрешение изображения и рассчитан размер памяти под него, и размер не выше допустимого, то может возникнуть только одна ошибка - не создан ресурс, то есть, файл не является изображением.

Все бы ничего, если бы такая ошибка возникала на первом загружаемом файле. Но если первый был корректный, а второй явная подстава, просто завершить работу означает, что в каталоге будет сохранен мусор.

Если же обработанные файлы сохранять в сессию под именами сгенерированными, как ключами, то и в функции processingIMG() можно завершать работу скрипта. Сохраненные до ошибки файлы будут удалены сборщиком мусора. Если же ошибок не возникло, то файлы из сессии переносятся в каталог, а ключи (имена файлов) одним запросом записываются в базу.

Каждый тип графического файла имеет заголовок, из которого можно узнать информацию о файле, включая его ширину и высоту. Считав по известному смещению данные о разрешении, можно их узнать функцией unpack(). Это позволит не сохранять на диск файл ради получения этой информации. Это на будущее как прикладная задача для изучения в общем полезных функций pack() и unpack().

Даже при соблюдении всех предосторожностей, тотальной проверки, каталог в который загружаются файлы извне и являющийся публичным, должен иметь соответствующие права. Права на запись в этот каталог получает владелец только на время записи в него файла, а после записи возвращает прежние. В каталоге должен быть запрещен запуск исполняемых файлов посредством .htaccess

#запретить листинг файлов каталога
Options -Indexes
#запретить выполнение скриптов в каталоге
php_flag engine 0
AddType "text/plain" .php .cgi .pl .fcgi .fpl .phtml .shtml .php2 .php3 .php4 .php5 .php6 .php7 .asp .jsp

Последний раз редактировалось laimas, 18.02.2018 в 10:31.
Ответить с цитированием
  #65 (permalink)  
Старый 18.02.2018, 18:23
Аватар для kupidon
Аспирант
Отправить личное сообщение для kupidon Посмотреть профиль Найти все сообщения от kupidon
 
Регистрация: 18.03.2016
Сообщений: 69

Сообщение от laimas
Возможно и много писанины получится, пока есть время написать можно (чем дольше читать будут и переваривать, тем больше у меня времени будет )
Это точно...

Спасибо Вам за такие развернутые ответы. Мне нужно время, чтобы все осознать. Про то, чтобы сделать просто, но с дырявым кодом я теперь понял..Многое придется перекроить теперь. Буду отписываться по мере работы.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
jQuery для загрузки страницы в <div> Dr.Holerik jQuery 12 11.10.2016 17:36
Надо добавить кнопочку для загрузки фоток в фотогалерею shooriks Серверные языки и технологии 5 01.04.2015 16:04
не закрывается DiV после загрузки в него файла sfumato jQuery 0 02.06.2011 21:05
Форма для ввода текста с расширенными функциями 0x22b Элементы интерфейса 0 01.09.2008 10:38
Поле загрузки файла kotofeich Элементы интерфейса 3 30.07.2008 11:24