Главная страница

Развитие языков программирования растёт с большой скоростью


Скачать 2.79 Mb.
НазваниеРазвитие языков программирования растёт с большой скоростью
АнкорKostern
Дата28.04.2022
Размер2.79 Mb.
Формат файлаpdf
Имя файлаKostelny_PHP-Junior-Kit.644079.pdf
ТипДокументы
#503693
страница9 из 14
1   ...   6   7   8   9   10   11   12   13   14

Hello world!


Here is another HTML tag
"; echo strip_tags($text); // Результат: Hello world!Here is another HTML echo strip_tags($text, "

"); // Результат:
Hello world!

Here is another HTML tag


?>
Это полезно использовать там где пользователь создаёт посты, например если найдется пользователь который захочет создавать сам теги

PHP: Junior Kit
189
в своем посте а мы этого не хотим, то тогда использовать эту функцию. А если мы хотим сохранить эти теги в базе данных но при этом, зашифровав их в специальные сущности надо воспользоваться функцией htmlspecialchars():
$to_encrypt = "
Это просто пример "; echo htmlspecialchars($to_encrypt);
// Результат: <p/a>Это просто пример<p/a>
?>
Если вы хотите избежать того чтобы пользователь вводил пробелы в начале или в конце строки воспользуйтесь функией trim():
?>
Хорошо, а теперь давайте создадим сами функцию которая могла фильтровать данные зарегистрированного пользователя, это уже более реальный пример:
$bad_symbols = array("\x27", "\x22",
"\x60", "\t", "\r", "\n", "+", "=", "-", "*", "%",
"?", "<", ">", "!");
$text = trim($text);
$text = strip_tags($text);
$text = str_replace($bad_symbols, "",
$text);
$text = str_replace(" ", "", $text);
}
?>

PHP: Junior Kit
190
Эту функцию вы можете использовать для фильтрации полей.
Такая функция сделает ваше приложение почти неуязвимым к SQL- инъекциям, но снова таки повторю. На практике все выглядит намного по-другому и сейчас применяются другие методы фильтрования данных, но то что я вам показываю даёт вам понять как все работает.
13.2
Безопасность файловой системы
Кроме какой-то фильтрации данных надо также реализовать безопасность файловой системы перед вредными файлами, которые могут быть загружены в файловую систему базы данных. Для этого надо будет сделать проверку форматов файлов чтобы в систему не могли попасть например php-файлы с помощью которых можно внедрить червей в приложение.
Как вы смогли понять то с помощью файлов загруженных в приложение можно делать атаки на само приложение. Давайте себе представим небольшую ситуацию когда в нас имеется приложение с пользователями и каждый пользователь, например, может удалять свою папку. Вот код который занимается удалением папки:
$username = $_SESSION["username"];
$file_delete = $_POST["file"]; unlink($file_delete); echo "Your directory has been deleted";
?>
Думаю уже некоторые читатели смогли заметить в чем здесь заключается проблема. Как вы можете здесь заметить то здесь нету

PHP: Junior Kit
191
проверки на пользователя, во-вторых вы можете заметить, что файл который надо удалить вводить пользователь и эти данные мы получаем через массив $_POST. А это значит, что любой злоумышленник сможет сделать атаку на файловую систему. То есть нам надо сделать так чтобы была проверка файлов, а также пользователя на авторизацию.
И кроме этого проверку на существование файла чтобы мы не получали ошибок если файл не будет существовать. Вот код нашего скрипта:
} else {
$username = $_SESSION["username"];
$file = basename($_POST["userfile"]);
$home = "/users/$username"; //
Устанавливаем папку пользователя
$path_to_file = "$home/$file"; //
Устанавливаем путь к указанному файлу пользователем if (file_exists($path_to_file) && unlink($path_to_file)) { echo "Файл был успешно удален.";
} else { exit("Файл не удалось удалить");
}
}
?>

PHP: Junior Kit
192
Теперь у нас есть проверка на авторизацию а также проверка пути файла, а точнее мы задаем путь к файлу и папке пользователя чтобы не было атак. Этот код стал более безопаснее. Но если бы у нас была дополнительная система, которая проверяла бы существование файла в файловой система но также и существование в базе данных – то это сделало бы система ещё более безопасной.
И при этом с помощью таблицы в базе данных можно было бы проверять авторство файлов по пользователю который авторизированный. Давайте сейчас сделаем пример со скриптом для загрузки файлов и при этом была также проверка формата файла который загружается на сервер.
Вот код данного скрипта:

$file_to_check = mime_content_type($_FILES["file"]["tmp_name"]); // С помощью этой переменной мы как раз и будем делать проверку формата файла, можете заметить какая здесь функция используется для этого if (in_array($file_to_check, array() )) { // В массиве которое указано в условии мы указали все форматы которые будут позволены для загрузки move_uploaded_file($_FILES["file"]["tmp_name"],
"home/uploads/" . $_FILES["file"]["name"]; echo "Файл был успешно загружен";
} else { exit("Произошла ошибка, или вы пытаетесь загрузить файл с другим форматом или ошибка в сети.");
}
?>

PHP: Junior Kit
193
Как видно из примера то сначала мы использовали функцию которая проверяет форматы, т.е. mime_content_type(). После этого в нашей логической конструкции мы с вами указали массив доступных форматов для файлов, а также сделали их проверку.
Если файл имеет один из разрешенных форматов которые мы указали, то тогда файл будет загружен в указанную директорию в функции move_uploaded_file(). В такой способ мы сделали довольно таки примитивную проверку форматов файлов.
Но что делать, если название файла будет иметь в себе какие-то запрещенные символы? В таком случае надо сделать поиск заданной подстроки в названии файла с помощью функции strstr(). В основном главное это чтобы загруженные файлы на сервер не могли навредить веб-приложению или украсть данные из БД.
На этом я завершу этот подраздел, и в следующем подразделе мы с вами поговорим об такой науке как – Криптография. Сейчас каждый разработчик должен знать хотя бы основы использования этой науки, поскольку шифрование и защита данных сейчас очень актуальная.
Поэтому переходим к следующему подразделу.
13.3
Криптография
Я уже упоминал как то об этой науке в этой книге. Повторю снова что это за наука. Криптография – это наука, которая занимается созданием шифров и защитой данных с помощью использования математических методов. То есть это как бы сказать наука об шифрах и шифровании.
В этом подразделе я вам расскажу об самом понятии шифров, какие есть их виды и для чего вообще они нужны. Начнём пожалуй с того что я расскажу немного истории об этой науке. Как не странно но начало этой науке дали великие древнегреческие ученые. Ну и вообще очень много современных наук появились благодаря этим талантливым и мудрым ученым.

PHP: Junior Kit
194
Первым очень простым инструментом который, использовался для того чтобы зашифровать сообщение являлась небольшая палочка которая называлась Скиталой. Скитала имела определенное число кутов и определенную длину. На палочку наматывалась лента как это показано на данном изображении:
-
Рис. 21 - Инструмент Скитала. Изображение было взято с
открытой энциклопедии Википедии.
Лента могла быть из пергамента или кожи, т.е. сделано с такого материала на котором можно было нормально писать сообщения.
Намотав ленту человек писал своё сообщение после чего передавал такую ленту человеку который хотел прочитать это сообщение. Человек который хотел прочитать сообщение также имел копию той же самой скиталы на которой было написано сообщение.
Если человек не имел копии той скиталы на которой было сообщение то он просто не мог прочитать сообщение. Это было только начало криптографии, дальше все становилось намного интереснее.
Следующей технологией, которая использовалась для шифрования был шифр Юлия Цезаря.
Внизу вы можете схему на которой показано как он работает:

PHP: Junior Kit
195
-
Рис. 22 - Алгоритм работы шифра Цезаря. Изображение было
взято с открытой энциклопедии Википедии.
Как вы видите, то здесь есть основной алфавит и алфавит с зашифрованными буквами. А точнее просто с измененной позицией букв в алфавите. Например, если мы хотим с вами зашифровать букву А то нам надо перейти на три символа вперед и тогда выбрать этот символ.
И именно тот выбранный символ это будет наша зашифрованная буква А. В нашем примере это буква D. Если у нас будет буква B то тогда это уже будет E. А если это С то буквой шифра будет F. То есть суть шифра заключается в том что если мы хотим с вами ч зашифровать букву то мы должны с вами двигаться на три символа вперед после чего выбирать этот символ.
В такой способом можно шифровать сообщения. Но шифр Цезаря довольно таки прост и его просто взломать. Двигаемся вперед в истории криптографии, и дальше на нас ждет Киевская Русь. Во время этой эпохи был созданный шифр который использовал алфавит древнерусского языка и алфавит древнегреческого языка.
Сообщение шифровалось по той схеме, что некоторые буквы просто заменялись на буквы древнегреческого алфавита. Если была древнерусская бука З – то есть земля, то ее могли заменить на греческую букву ζ – дзета.

PHP: Junior Kit
196
Приблизительно вот так происходило шифрование в то время.
Конечно же сейчас я не буду полностью вам рассказывать историю всей криптографии потому что это может занять очень и очень много времени и страниц этой книги. Поэтому я рассказываю только ключевые и интересные моменты чтобы читатель мог немного отдохнуть от программирования. В эпоху Возрождения был созданный шифровальный диск Альберти. Вот как он выглядел:
-
Рис. 23 - Шифровальный диск Альберти. Данное изображение
было взято из портала ipo.spb.ru
Данный шифр очень сильно напоминает шифр Цезаря поскольку здесь так же используется схема с заменой символов в шифре. Только здесь уже нам надо перемещаться на 3 буквы вперед. Суть заключается в том что шифр мог иметь заданные правила шифрования, а точнее уже установленную последовательность букв.
Как вы можете заметить, то на изображении есть два диска. На первом диска были буквы алфавита которые мы хотели использовали когда нам надо было зашифровать определенный символ. А внизу располагался уже зашифрованный вариант этих букв. Первый диск служил указателем для шифрованных букв. То есть например, если мы хотим зашифровать слово FAKE, то мы просто должны были бы по очереди смотреть буквы на двух дисках после чего делать шифрование.

PHP: Junior Kit
197
Вот как бы выглядело это слово в зашифрованном виде - indj.
Конечно же, данный шифр мог взломать только тот у которого был такой же самый диск с помощью которого и шифровалось сообщение. Такая же ситуация как и Скиталой. Такой шифр по сути невозможно было взломать. Двигаемся дальше, и следующей эпохой в нас была Эпоха
Нового Времени. В это время был создан шифр Виженера, это была большая матрица с ключом который использовался для того чтобы зашифровать любо расшифровать сообщение.
Внизу есть большая схема с шифром Виженера:
-
Рис. 24 - Демонстрация работы шифра Виженера
Матрица выглядит довольно таки сложной. С первого раза вы не сможете понять все сразу, но попробую все объяснить. Как я и говорил у нас есть ключ который себе создаем для того чтобы шифровать и дешифровать данные.
Ключом может быть определенное слово, например, у меня это будет слово cool. И пусть слово которое мы хотим с вами зашифровать это будет norma. И теперь смотрите на матрицу, с левой стороны вы видите столбец алфавита - это столбец для букв ключа. А сверху находиться ещё один столбец и это столбец для букв данных которые мы хотим зашифровать.

PHP: Junior Kit
198
Теперь если мы с вами хотим зашифровать слово norma то тогда нам надо для начала искать букву C в столбце для букв ключа и букву N в столбце для букв исходных данных. И в результате мы должны с вами найти клетку с буквой P. То есть вы делаете шифрование по координатах как это показано на изображении выше с буквой F.
Это была эпоха Нового времени. Дальше через несколько сотен лет во время второй мировой войны данная наука очень сильно понадобилось в вооружение многих стран для защиты своих военных данных и документов.
Великим толчком для развития компьютеров или как на то время их называли ЭВМ(Электрическая-Вычислительная-Машина) как раз и стала шифровальная машина Енигма, которая была создана немецкими учеными для немецкой армии на то время. Енигму вы можете увидеть на изображении которое показано ниже:
-
Рис. 25 - Внешний вид шифровальной машина “Енигма”. Данное
изображение было взято с веб-сайта rtr.md
Объяснять то как она работает не буду, но скажу очень важный факт что благодаря тому что удалось взломать шифр данной машины то войну удалось сократить на целых 3 года. Ну а что было дальше с этой великой наукой после второй мировой войны?

PHP: Junior Kit
199
Начался появляться новый раздел криптографии – Цифровая криптография. То есть криптография, которая используется в компьютерных системах для цифрового шифрования данных. Цифровая криптография позволяет автоматизировать шифрование данных, а также саму скорость шифрования и дешифрования. То есть ученому теперь не приходится крутить какие вентели для того чтобы зашифровать часть данных, все автоматизировано и нажав одну кнопку программа сама шифрует данные а ученому остается только подобрать параметры шифрования.
Сейчас знание криптографии и информационной безопасности это очень важно для любого разработчика. Давайте с вами в общем поговорим об шифрах и об их видах. Шифр это набор определенных правил и параметров для того чтобы защитить данные. Если кратко, то это просто алгоритм для защиты данных. Шифры имеют ключи которые используются для того чтобы зашифровать или расшифровать данные.
Ключи имеют выбранный алгоритм шифрования, а также имеют длину в битах. Шифры бывают трех видов:
● Симметричные – это шифры, которые используют только один ключ для шифровки и дешифровки данных. Длина таких шифров может быть от 16 до 256 бит.
● Асимметричные – это шифры, которые имеют два ключа для шифрования и дешифрования данных. Первый ключ называется публичным и используется для того чтобы зашифровать данные. Второй ключ называется приватным ключом который используется для того чтобы расшифровать данные.
● Хэш-функции – это уже цифровые подписи которые используются для того чтобы подтвердить свою личность.
Внизу показана схема работы симметрического шифра:

PHP: Junior Kit
200
-
Рис. 26 - Демонстрация работы симметричного шифрования
Как вы можете заметить, то на данной схеме есть два клиента.
Первый клиент делает шифрование сообщения с помощью ключа который вы можете увидеть сверху схемы. Данный ключ используется для того чтобы зашифровать и расшифровать сообщение.
После шифрования сообщения клиент передает сообщение по сети второму клиенту, который получив его делает дешифрование сообщения с помощью того же самого ключа с помощью которого и была сделана шифровка сообщения.
-
Рис. 27 - Демонстрация работы ассиметричного шифрования

PHP: Junior Kit
201
Здесь уже схема работы ассиметричного шифрования. Я упростил схему забрав клиентов а показав только основные моменты работы этого типа шифров. Как я и говорил, публичный ключ используется для того чтобы зашифровать данные, а приватный чтобы их расшифровать. То есть если бы у нас было бы два клиента то это выглядело вот так. Первый клиент используя свой публичный ключ и имея публичный ключ второго клиента делает шифрацию сообщения, после этого он передает это самое сообщение второму клиенту.
Который в свою очередь делает дешифрацию этого сообщения. И в результате он может его прочитать и ответить первому клиенту. Думаю вы уже поняли в чем смысл работы? На всякий случай повторю, публичный ключ - для того чтобы зашифровать сообщение, а приватный ключ - для того чтобы дешифровать сообщение.
Теперь, давайте перейдем к последнему виду шифров, т.е. к хэш- функциям. Как я уже и говорил то хэш-функции это цифровые подписи для того чтобы подтвердить свою личность. Некоторые могут не знать что такое хэш-функция, поэтому скажу сразу, что это преобразование массива входных данных любой длины в битовую строку определенной длины, который выполняется определенным алгоритмом.
Простым примером работы хэш-функции является схема, которая показана ниже:
-
Рис. 28 - Демонстрация работы хэш-функции

PHP: Junior Kit
202
Мы просто даём входные данные, после чего получаем выходные данные. После того как мы с вами получаем цифровую подпись - мы можем ее прикрепить к нашему с вами зашифрованному сообщению. Мы могли конечно же рассматривать все очень подробно. К примеру, то как работает симметричное шифрование на примере какого-то определенного шифра, но мы этого не делали по одной простой причине. Работа алгоритмов шифрования очень сложная изнутри.
Например, чтобы понять как работает алгоритм AES(а об этом мы алгоритме мы поговорим позже) вам бы понадобились для этого знания математического анализа и статистики. А все потому что криптография решает проблемы шифрования с помощью математических методов.
В следующем подразделе мы с вами поговорим об том какие есть популярные шифры для защиты данных. Кратко рассмотрим их работу, а также познакомимся с блочными и потоковыми шифрами.
13.4
Шифры
Мы уже с вами знаем, какие существуют виды шифров. Теперь можно поговорить об том какие именно шифры используются на данный момент для шифрования данных. Я сделал небольшой time-line чтобы вам показать как появлялись шифры на этот свет:

PHP: Junior Kit
203
-
Рис. 29 - Временная линия с демонстрацией появления популярных
шифров
Здесь я вывел одни из самых популярных шифров которые сейчас используются для того чтобы шифровать данные. Первый алгоритм, который начинает этот time-line является симметричный шифр DES. Без аббревиатуры это звучит вот так Data-Encryption-Standart.
То есть если перевести это на русский язык, то это будет звучать как Стандарт-Шифрования-Данных. И да, это реально стандарт шифрования данных который используется. Переходим к следующему шифру, и дальше у нас идет популярный ассиметричный шифр RSA.
Название данного шифра походит от фамилий разработчиков данного шифра, т.е. Rivest, Shamir и Adleman. Сейчас это один из самых популярных шифров, он используется в приложении Telegram для шифрования сообщений. Но Telegram использует не только шифр RSA, оно использует также другие шифры которые показаны в time-line.
Дальше в нашем time-line идет цифровая подпись MD5, аббревиатура которой расшифровуется как Message-Digest-5 – Дайджест Сообщения 5.
Данный алгоритм можно использовать не только как хэш- функцию для цифровых подписей, но также как простой генератор имен для загружаемых файлов в веб-приложение. Это сделает систему файловую систему безопаснее. И последний шифр, который у нас остался это симметричный шифр AES или Advanced - Encryption - Standart –
Расширенный-Стандарт-Шифрования. Ну и как не странно это также стандарт шифрования, это понятно также из названия шифра, но кроме этого данный шифр также используется в приложении Telegram.

PHP: Junior Kit
204
Хорошо, я вас познакомил с популярными шифрами. Об их работе мы поговорим позже, а сейчас же чтобы двигаться нам дальше нам надо узнать что такое блочное и потоковое шифрование.
Блочное шифрование это шифрование, которое используется в симметричных шифрах для более безопасного шифрования. Существует много разных режимов блочного шифрования, и выбирать стоит той который более подходит под решаемую задачу. Но вопрос, что же такое блочное шифрование?
Внизу показана схема, которая как раз и демонстрирует работу блочного шифрования:
-
Рис. 30 - Схема демонстрирующая работу блочного шифрования
на примере режима блочного шифрования ECB
Во-первых, блочное шифрование это когда исходный текст разбивается на блоки которые имеют длину ключа, которым будет шифроваться сообщение. Блоки в свою очередь потом берутся и шифруются по отдельности ключом.
В результате вектор инициализации задает случайную последовательность для этих блоков. И в конце все эти блоки собираются

PHP: Junior Kit
205
в одно целое и у нас получается шифротекст. Т.е. зашифрованные данные.
Теперь посмотрите на схему и сверху вы как раз и сможете увидеть блоки исходного текста. И дальше все идет так как я вам объяснял только что, т.е. дальше идет обработка этих блоков ключом и алгоритмом шифрования. И как показано в конце схемы – то все это становится одним целым и мы получаем зашифрованные данные.
Довольно таки просто. Мы только что с вами рассмотрели режим блочного шифрования ECB(Electronic-Codes-Book) или Электронная-
Книга-Кодов.
Существует много других режимов блочного шифрования.
Например, CBC который мы сейчас с вами рассмотрим.
-
Рис. 31 - Схема демонстрирующая работу режима блочного
шифрования CBC
На схеме есть вектор инициализации, который задает случайную последовательность блоков. Если посмотреть направо, то там дальше идут другие блоки в которых используется тот самый вектор инициализации который использовался в самом начале для шифрации первого блока.
И так вектор инициализации переходит к каждому следующему блоку и так пока не будет полностью зашифровано сообщение. Хорошо, только что мы с вами рассмотрели, что такое блочные шифры, а теперь давайте рассмотрим что такое потоковые шифры.

PHP: Junior Kit
206
Потоковый шифр – это симметричный шифр, в котором каждый символ исходного текста преобразуется в символ шифротекста в зависимости от ключа и его расположения в потоке исходного текста.
Посмотрите на схему которая показана ниже:
-
Рис. 32 - Схема демонстрирующая работу потоковых шифров
Генератор гаммы генерирует потоковые шифры для того чтобы зашифровать исходный текст. После этого происходит процесс шифрования и мы получаем шифротекст. И дальше на схеме показывается процесс дешифрации шифротекста.
Потоковые шифры делятся на два типы:
● Синхронизирующие – это потоковые шифры, в которых поток ключей генерируется независимо от исходного текста и шифротекста.
● Самосинхронизирующее – это потоковые шифры, в которых поток шифров создается функцией ключа и зависит от определенного числа символов шифротекста.
Каждый из этих двух типов потоковых шифров имеют свои плюсы и минусы. Например, в синхронизирующих потоковых шифрах или СПШ есть плюс в том что есть отсутствие эффекта распространения

PHP: Junior Kit
207
ошибок. То есть, только один бит который был искаженным будет зашифрован неверно.
Внизу я вывел другие плюсы и минусы СПШ:
+ предохраняет от любых вставок и удаления шифротекста, если они будут то они будут обнаружены и это приведет к потере синхронизации.
- СПШ уязвимы к изменению отдельных битов шифрованного текста. Если злоумышленнику известный исходный текст - то он сможет изменить биты так чтобы расшифровать шифротекст.
Внизу показаны плюсы и минусы
АПШ или
Самосинхронизирующих Потоковых Шифров:
+ Размешивание статистики исходного текста. То есть поскольку каждый символ исходного текста влияет на шифротекст, то статистические свойства исходного текста распространяются на весь шифротекст. И через это АПШ может быть устойчивым к атак на основе избыточности исходного текста, чем СПШ.
- распространенные ошибки, то есть каждом неправильному биту соотвествует N ошибок в исходном тексте.
- чувствительность к вскрытию повторной передачей. То есть, при многих передачах шифрования и дешифрования того самого шифротекста могут появиться ошибки в битах.
Мы с вами рассмотрели, какие существуют шифры и их виды. А что же можно сказать об тех технологиях которые существуют для того чтобы реализовать способы шифрования в своем приложении. Если вы хотите попробовать что то зашифровать то можно воспользоваться проектом AES Encryption.
AES Encryption как понятно из названия то это веб-сайт который позволяет тестировать шифр AES, все что вам надо это только симметричный ключ данного шифр, длиной от 128 до 256 бит. Ну и конечно же данные которые вы хотите зашифровать.

PHP: Junior Kit
208
Ключ можно достать из веб-сайта
AES
Security https://asecuritysite.com/encryption/keygen
. На данном веб-сайте вы сможете подобрать все нужные параметры для вашего симметричного ключа, главное подобрать длину ключа и кодовое слово которое будет зашифровано в ключе.
Вы получите все данные об вашем ключе, также вы сможете просмотреть вектор инициализации который используется в вашем ключе на данном сервисе. Но нас интересует именно ключ, поэтому скопируйте ключ после переменной key. После генерации ключа можете отправиться на AES Encryption и вы можете заполнить поля так как я заполнил на изображении показанном ниже:
-
Рис. 33 - Форма для ввода данных чтобы зашифровать
произвольные данные
После того как вы ввели все данные в поля нажмите на кнопку
“Encrypt”, и в результате вы должны получить шифротекст тех данных которые вы ввели в поле для исходного текста. У меня это выглядит вот так:
-
Рис. 34 - Вывод результата шифрования на AESEncryption

PHP: Junior Kit
209
То есть я зашифровал своим ключом фразу “Hello world!”. У вас конечно же с вашим ключом получится совсем другой результат. Думаю некоторые читатели которые сразу зашли на данный веб-сайт заметили пункт в меню под название «РНР». И если вы перейдете по данной ссылке то вы попадете на страницу где вы сможете взять и скопировать код класса который сможет реализовать функции шифрования с помощью алгоритма AES.
Класс не представляет из себя ниченого сложного, это просто набор функций для шифрования и дешифрования данных с помощью алгоритма AES. Скопируйте данный код и сохраните в отдельном файле назвав его при этом aes.php. После этого создайте другой файл который должен называться cipher.php, сейчас мы попрактикуемся с шифрованием в РНР, вставьте в файл cipher.php этот код:
$data_to_encrypt = “Encrypt me!”;
$pass_for_key = “Cool key”;
$length = 256;
$aes = new AES($data_to_encrypt,
$pass_for_key, $length);
$encrypted = $aes->encrypt();
$aes->setData($encrypted);
$decrypted = $aes->decrypt(); echo “Результат после шифрования: ” .
$encrypted . “
”; echo “Результат после дешифрования: ” .
$decrypted . “
”;
?>

PHP: Junior Kit
210
Теперь я объясню что как и к чему. Сначала мы подключаем класс к нашему скрипту, чтобы мы могли воспользоваться его функциями.
После этого мы создаём 3 переменные, которые нам понадобятся когда мы будем создавать объект нашего класса. Этими переменными являются
$data_to_encrypt, $pass_for_key и $length, Первая переменная содержит данные, которые мы хотим с вами зашифровать. Вторая же хранит в себе кодовую фразу для нашего ключа. И третья содержит данные об длине блока.
После того как мы создали с вами эти переменные мы создали объект класса алгоритма AES, указав при этом 3 созданные нами переменные как параметры класса. Дальше мы сделали шифрование данных и создали переменную $encrypted который содержит в себе зашифрованные данные. А после этого мы создали переменную
$decrypted, которая уже хранит в себе дешифрованные данные данных которые мы зашифровали. И в конце нашей программы мы сделали вывод сначала зашифрованных данных, а потом уже дешифрованных данных.
В такой способ мы смогли увидеть как работает шифрование с использованием данного класса. Рекомендую читателю сейчас по пробовать запрограммировать что то свое. Например, задать свою длину для блока или указать другие данные которые вы хотите зашифровать.
Теперь я скажу такую вещь, только что мы с вами воспользовались библиотекой. Стоп, не надо думать что мы только что брали и использовали какую то библиотеку для того чтобы получить какую то книгу и т.п.
Нет, мы с вами воспользовались библиотекой которая в немного расширила наш с вами функционал. То есть в нашем случае добавила возможность шифрования данных с помощью алгоритма AES.
Библиотека в программировании это как бы сказать свое родное расширение для определенного языка программирования. Библиотеки облегчают работу программисту, что позволяет более эффективно разрабатывать приложения. На данный момент библиотек очень много и

PHP: Junior Kit
211
очень часто программисты пользуются именно библиотеками, а не функциями самого языка программирования. И правильно, зачем же
“изобретать велосипед”? Конечно же, «изобретать велосипед» хорошо только тогда, когда ваш «изобретенный велосипед» будет лучше за уже созданные «велосипеды».
Поэтому я хочу сказать читателю, что если он будет разрабатывать что то в будущем, то пусть обязательно использует библиотеки и разные расширения чтобы тратить меньше времени на разработку. Это стандарт использовать библиотеки и любые другие инструменты, которые позволяют облегчит разработку. Мы с вами установили и воспользовались библиотекой, которая добавила функционал шифрования с алгоритмом AES. Класс был довольно таки маленьким, но он все равно выполнял те математические операции которые выполняются во время шифровании с алгоритмом AES.
Существует очень много других криптографических библиотек для РНР, которые добавляют алгоритмы шифрования популярных шифров. И сейчас мы с вами познакомимся с ещё одной такой библиотекой. А точнее с расширением. В официальной документации вы можете найти статью об том, какие существуют расширения на РНР для реализации криптографических операций. Первым таким расширением является расширение PECL.
PECL имеет множество пакетов которые могут установиться вместе с этим расширением для того чтобы расширить ещё больше функционал в сторону криптографии в РНР. Официальной документацией является веб-сайт https://pecl.php.net. Именно с этого веб-сайта вы можете установить данное расширение. Самым простым способом установки PECL это будет скачивание zip-архива. Посмотреть все доступные версии данного расширения, а также все доступные zip-архивы можно просмотреть за адресом: https://pecl.php.net/package/zip.

PHP: Junior Kit
212
Я выбрал версию 1.15.0 данного расширения. В zip-архиве данного расширения вы сможете найти файлы данного расширения, но также и просмотреть примеры с использованием данного расширения. В официальной документации РНР есть отдельная статья об том как установить PECL и как его использовать. А теперь давайте уже перейдем к установке данного расширения. Во-первых, для того чтобы установить
PECL нам понадобиться система PEAR(это также расширение если что).
Веб-сайтом данной системы является http://pear.php.net.
Для установки PEAR нам понадобиться просто взять и установить файл установки go-pear.phar. Поэтому перейдите в раздел установки(download), и следует дальнейшим инструкциям. Ссылка на установку файла показана на изображении ниже:
-
Рис. 35 - Ссылка на установку PEAR на официальном сайте
проекта PEAR
Скачайте этот файл и переместите его в папку php которая находиться в папке локального сервера XAMPP. После этого откройте командную строку и перейдите в папку php нашего локального сервера.
Если вы не знаете, как это сделать, то это можно сделать с помощью команды cd которая используется для перехода в папки. Когда вы откроете командную строку, то вы сразу заметите что вы будете находиться на диску C: в папке пользователя. Но это ещё, если вы пользуйтесь операционной системой Windows.

PHP: Junior Kit
213
У меня xampp установлен в корневой папке на диску С: и сейчас мы перейдем в папку локального сервера. Чтобы перейти в корневую папку диска С: надо прописать такую команду:
C:\Users\User>cd /
C:\>
Как вы можете заметить то в такой способ мы перешли в корневую папку диска С:. Внизу показано то как я перешёл в папку с локальным сервером:
C:\>cd xampp
C:\xampp>cd php
C:\xampp\php>
Или конечно же, можно это сделать вот так:
C:\>cd xampp/php
Но если вы установили XAMPP на диск D:, то чтобы перейти на диск D: выполните следующую команду:
C:\>cd /d D:\
D:\>
Теперь после того как вы перешли в папку из РНР нашего локального сервера то вы можете начать установку PEAR. Скачайте и переместите файл go-pear.phar в папку php. В документации по установке PEAR была описана команда, которая начинает установку
PEAR, установка делается с помощью этой команды:
C:\xampp\php>php go-pear.phar
В этой команде вы можете заметить что мы обращаемся к приложению php.exe которое есть в данной папке. Именно это приложение отвечает за работу РНР на локальном сервере. После запуска этой команды, РНР спросит устанавливаем ли мы системную или локальную копию PEAR. Мы конечно же устанавливаем системную копию поэтому просто жмем кнопку enter. После этого РНР выведет список папок, в которые он установит файлы, мы также на это не обращаем внимания а просто жмем кнопку enter, поскольку мы хотим установить PEAR по умолчанию.

PHP: Junior Kit
214
Дальше начнется установка файлов данного расширения. Но на этом установка расширения не заканчивается, теперь нам надо взять и отредактировать системный файл РНР - php.ini. Данный системный файл находиться в папке РНР. Откройте данный файл в редакторе кода после чего добавьте в конец файла такую строку: include_path = “.;c:\php\pear”
Сохраните файл. Добавив эту строку кода, мы как раз и подключили данное расширение к РНР. И мы можем теперь пользоваться его функционалом. Дальше нам надо будет запустить файл регистра данного расширения. Просто откройте его, файл регистра имеет название
PEAR_ENV.reg
. Дальше перезапустите ваш локальный сервер, если он у вас был включен. Перезапустите также и командную строку. Это чтобы расширение запустилось, и было зарегистрировано в системе.
И теперь попробуйте протестировать расширение с помощью такой простой команды как проверка версии расширения: pear version
После этого если у вас выведутся данные об версии расширения, то это будет значить что вы установили успешно расширение PEAR.
Теперь вы умеете устанавливать расширения на РНР, и частенько это может понадобиться, когда вы будете что то разрабатывать. И главное что вы это пробовали на практике. Давайте вернемся к нашей с вами теме об установке PECL. Но перед этим хочу сказать, что только что установленное расширение используется для повышения безопасности, с помощью дополнительного функционала.
А теперь давайте поговорим об установке в PECL. Но перед этим скажу, что PECL это не одно целое и единое, а это отдельный сборник расширений для РНР работающих через PEAR которые мы с вами потом можем выбрать для своих целей. На официальном сайте мы можем найти страницу на которой мы можем просмотреть все доступные для нас расширения которые разделены по разных категориях. И именно там можно наткнутся на категорию Encryption что переводиться как шифрование.

PHP: Junior Kit
215
На данный момент есть только 6 PECL расширений, которые позволяют реализовать алгоритмы шифрования. Сейчас мы с вами установим расширение для PECL, которое имеет название mcrypt. Как раз с ним мы сейчас и поработаем.
Установить данное расширение можно за адресом https://pecl.php.net/package/mcrypt
. Скачайте .tgz-архив расширения и разархивируйте его в папку pear, которая находиться в папке php. Дальше вам надо подключить данное расширение через системный файл php.ini: include_path = “.;c:\php\pear\mcrypt-1.0.1”
После этого вы сможете воспользоваться функциями данного расширения. Теперь давайте протестируем данное расширение, для этого мы создадим небольшой тестовый скрипт. Создайте новый скрипт под название mcrypt.php и добавьте в него такой код:
$key = hash("sha256", "my key", true); print_r($key);
?>
Теперь я вам объясню вам, что мы только что сделали. Это была всего лишь одна строка, но ей нам хватить для того чтобы понять работает ли наше расширение. Мы создали хэш, а точнее цифровую подпись с алгоритмом SHA256, после этого мы вывели данные ключа на страницу чтобы можно было увидеть какой-то результат того что мы только что сделали.
Хэш мы создали с помощью функции hash(), сначала мы указали алгоритм, который хотим использовать для создания хэша.
Дальше мы указали секретное кодовое слово для хэша. Если в последнем параметре нашей функции будет поставлено значение равное истине, то мы получим результат в виде необработанных двоичных данных. А если же будет значение равное ложи - то получим данные в шестнадцати разрядной кодировке.

PHP: Junior Kit
216
Давайте теперь усложним наш пример и сделаем полноценное шифрование определенных данных. Вот код:
$key = hash("sha256", "this is a secret key");
$input = "Let us meet at 9 o'clock at the secret place.";
$td = mcrypt_module_open("rijndael-128", "",
"cbc", "");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td),
MCRYPT_DEV_URANDOM); crypt_generic_init($td, $key, $iv);
$encrypted_data = mcrypt_generic($td, $input); mcrypt_generic_deinit($td); mcrypt_module_close($td);
?>
Вы можете заметить переменную $input, эта переменная это данные, которые мы хотим с вами зашифровать. Дальше у нас идет переменная, $td внутри которой мы выбираем алгоритм шифрования, а также режим блочного шифрования для данного алгоритма. В нашем примере мы выбрали алгоритм rijndael-128, ключ имеет длину 128 битов, это можно понять из названия самого алгоритма. А также я думаю, вы заметили здесь, что мы выбрали режим блочного шифрования CBC.
После этого идет вектор инициализации который генерируется с помощью функции mcrypt_create_iv(). И только после того как мы сгенерировали все нужные для нас компоненты мы начинаем шифрование с помощью команды mcrypt_generic_init(). Внутри этой функции мы как раз и указали сгенерированные нами компоненты для шифрования. После этого мы создали переменную, $encrypted_data
– внутри которой содержаться зашифрованные данные.

PHP: Junior Kit
217
И в конце скрипта мы удаляем компоненты, которые использовались для шифрования. Конечно же, когда вы перейдете на страницу с данным скриптом то вы не увидите никакого результата, поскольку мы не воспользовалось ни одной из команд для вывода данных. Вы можете сделать вывод данных с помощью одной из команд для вывода данных, а точнее команд для вывода данных об переменных.
Что ж, какой мы можем сделать вывод из того что мы с вами сделали?
Во-первых, мы научились, как можно устанавливать расширения.
Во-вторых, мы научились использовать шифры, а также можем объяснить их работу и классификацию. Во-третьих, мы можем реализовать шифрование данных с помощью РНР. Мы очень много чего с вами сделали в данном подразделе, и я считаю, что настало время переходить к следующему подразделу. Я также рекомендую читателю заглянуть в официальную документацию по расширению Mcrypt.
Сделайте несколько примеров, и рассмотрите какие есть функции в данном расширении и обязательно сделайте практику с ними.
Следующий подраздел будет об шифровании паролей в РНР. А также об хранении паролей в базе данных в зашифрованном виде. Криптография – это очень сложная тема для обсуждения на конференциях и не только.
Криптографию сложно усвоить, поскольку криптография это дело нашей с вами безопасности и поэтому все надо очень четко рассмотреть и создать чтобы система была безопасной.
13.5
Хэширование паролей
Простым примером того для чего нужно хэширование/шифрование паролей в вашем приложении является ситуация которая случилась в 2016 году с приложением Твиттер. В этом
2016 году с базы данных Твиттера было украдено 30 миллионов аккаунтов, но проблема заключается в том что пароли хранились в незашифрованном виде.

PHP: Junior Kit
218
Если бы пароли хэшировались то такой ситуации не было бы. И компания не понесла бы убытки. Популярными алгоритмами для хэширования паролей являются md5 и sha256. Но вообще в РНР 5.5 для этого были добавлены отдельные функции, которые позволяют хэшировать пароли. Давайте рассмотрим с вами простой пример хэширования пароля с использованием функции password_hash():
$password = "Hello";
$hash = password_hash($password,
PASSWORD_DEFAULT); print_r($hash);
?>
Сохраните данный скрипт и протестируйте его в браузере. Вы сможете увидеть вывод данных хэшированного пароля. Некоторые читатели смогли здесь заметить, что в функции мы указали вторым аргументом функции константу PASSWORD_DEFAULT, которая делает хэширование по умолчанию. Когда идет хэширование пароля, то к паролю добавляются фальшивые данные которые называются salt(соль).
Это подвышает безопасность и позволяет обмануть злоумышленника.
Если мы хотим проверить был ли введенный пароль пользователем верно, то надо просто взять хэш и пароль из базы после чего просто проверить этих два элемента с помощью функции password_verify():
Если получим значение которое равно истине то значит пароль введен верно

} else {

}
?>

PHP: Junior Kit
219
Если у вас будет такая ситуация что вам понадобиться узнать какие-то данные об хэшированном пароле то вам надо будет воспользоваться функцией password_get_info(), которая выводит данные в виде массиве с тремя элементами:
● algo – алгоритм который использовался для хэширования.
● algoName – название алгоритма который использовался для хэширования.
● options – опции которые использовались при хэшировании.
Если нам понадобиться изменить параметры salt, то мы должны воспользоваться функцией password_needs_rehash():
["cost"] => 12)) {
$hash = password_hash($password,
PASSWORD_DEFAULT, ["cost"] => 12);

} else {

}
?>
В этом коде вы можете увидеть то, как мы изменением параметры salt, меняя длину данного параметра. Это был подраздел об хэшировании паролей, это важно сейчас. Тема криптографии сейчас очень актуальна и поэтому криптографию стоит изучать разработчику. Я уже об этом говорил. Сейчас используются множество библиотек и фреймворков которые в несколько раз облегчают жизнь программисту.
Сейчас приложения не пишутся с нуля, у них уже есть готовый
«каркас» и программисту остается только строить своё приложение на данном каркасе.

PHP: Junior Kit
220
Вопросы и упражнения для самоконтроля
1. Какие существуют методы безопасности в РНР?
2. Какие есть виды атак на приложение?
3. В какой способ злоумышленник может навредить базе данных?
4. Для чего нужна фильтрация данных?
5. Какие есть методы/функции для фильтрации данных?
6. Напишите скрипт который не допускал присутствия цифр в поле формы которая имела бы два поля.
7. Что такое криптография и для чего она нужна?
8. Расскажите немного об истории криптографии. (Необязательно)
9. Какие существуют виды шифров а также расскажите об их разнице и об их работе.
10. Что такое блочное шифрование и потоковое шифрование? А также в чем разница этих двух видов?
11. Расскажите об часто используемых шифрах.
12. Для чего нужны ключи шифрам?
13. Напишите код с который шифровал такие данные «Hello world!».
14. Какие есть способы хэширования паролей?
15. Какие алгоритмы применяются для хэширования паролей?
16. Зачем нужно хэшировать пароли?
17. Какие есть функции для хэширования паролей?

PHP: Junior Kit
221 14
Работа с другими веб- службами
В этом разделе речь пойдет уже о том как можно работать с другими веб-службами с помощью Прикладного-Программного-
Интерфейса или более правильное название API(Application-Program-
Interface). Именно с помощью API мы можем авторизоваться с помощью любой соц. сети в любом приложении, где это программным путем поддерживается. Например, может быть веб-приложение, где можно авторизоваться с помощью своего аккаунта Твиттера.
В этом случае, для авторизации будет использована API Твиттера, которое было создано разработчиками самого Твиттера. Или если, например, мы захотим с вами авторизовать в каком то приложении с

PHP: Junior Kit
222
помощью аккаунта в Facebook, то здесь уже будет использовано Facebook
API.
То есть многие сервисы сами создают свою API для того чтобы им могли пользоваться другие разработчики чтобы ввести какие то дополнительные сервисы, чтобы взаимодействовать с сервисом который и дает данное API. Перед тем как мы реально начнём работать с API какого- то сервиса, то мы должны понять, что такое JSON, а потом уже научиться делать запросы на получение JSON данных с помощью PHP. Поэтому первый подраздел этого раздела будет об JSON.
14.1
Что такое JSON?
Аббревиатура JSON расшифровывается как JavaScript-Object-
Notation. Т.е. нотация JavaScript объектов, это не язык программирования.
JSON это текстовый формат обмена данными между компьютерами, а также в сети. JSON очень легко позволяет передавать определенные данные в сети. Кроме JSON’а данные можно также передавать в формате
XML. Но мы с вами будем говорить именно об JSON’е. В РНР есть специальные функции для того чтобы кодировать и декодировать JSON информацию и потом получать её в виде массива.
Давайте с вами рассмотрим небольшой пример массива JSON- данных:
{
"firstName": "Mike",
"lastName": "Freeman",
"city": "Amsterdam",
"job": "Web-developer",
"contactData": [
"phoneNumber": "300231134",
"e-mail": "mikefree@cool-app.com",
]
}

PHP: Junior Kit
223
Теперь давайте я вам объясню, что из себя представляют из себя эти данные. Во-первых, вы видите, что мы как бы сказать объявляем массив внутри которого как раз и находятся JSON-данные. Эти JSON- данные мы можем передать или просто хранить. Здесь вы можете увидеть первые элементы это firstName, lastName, city, job и массив contactData
. Думаю вы уже заметили что здесь есть ключ и значение к этому ключу. Заметьте то как создаются эти элементы, а также с помощью какого оператора делается присвоение данных для этих ключей.
(Подсказка - с помощью оператора : ).
Элемент contactData это массив который содержит элементы из данными для контакта. Для примера мы будем работать с Star Wars API чтобы понять то как все работает. Попробуйте создать какие то свои
JSON данные. Т.е. создайте свой массив, в котором вы сами будете добавлять свои объекты и сами выбирать что там должно быть. Вот ещё один пример, чтобы больше закрепить материал:
{
"name": "PHP Junior Kit",
"description": "Book about programming with PHP",
"author": "Demian Kostelny"
"tags": {
"Programming",
"PHP",
"Web-development"
}
}
Здесь вы уже видите массив tags который имеет в себе просто элементы, но не элементы которые имеют ключ и значение. Сделайте несколько простых файлов с JSON данными, чтобы большие закрепить материал. А теперь мы переходим к следующему подразделу, в котором мы будем работать с JSON и PHP.

PHP: Junior Kit
224 14.2 JSON и PHP
Для того чтобы работать в РНР с JSON как я уже и говорил есть специальные функции. Давайте представим ситуацию, когда нам надо передать определенные данные по сети и нам надо создать массив с JSON данными. Чтобы создать массив с JSON данными в РНР нам для начала надо просто создать массив в РНР который, содержал бы в себе элементы
JSON массива:
$json_data = array(
"firstName" => "Mike",
"lastName" => "Freeman",
"job" => "Web-developer",
"contactData" => array(
"phoneNumber" => "3001300",
"e-mail" => "mikefree@cool-app.com"
)
);
?>
Как вы можете увидеть, то здесь мы просто перевели JSON данные в простой РНР массив. Чтобы закодировать этот массив в JSON данные надо воспользоваться функцией json_encode():
$json_data = array(
"firstName" => "Mike",
"lastName" => "Freeman",
"job" => "Web-developer",
“contactData" => array(
"phoneNumber" => "3001300",
"e-mail" => "mikefree@cool-app.com"
)
);

PHP: Junior Kit
225
$encoded = json_encode($json_data); print_r($encoded); // Заметьте разницу между этим выводом данных print_r($json_data); // И этим выводом данных
?>
Результатом этого кода будет такая строка в виде JSON-данных:
{"firstName": "Mike", "lastName": "Freeman",
"job": "Web-developer", "contactData":
{"phoneNumber": "3001300", "e-mail": "mikefree@cool- app.com"}}
В такой способ можно брать кодировать простые массивы в JSON данные, после чего брать их и передавать по сети. А если нам надо будет декодировать JSON данные, то для этого надо воспользоваться функцией json_decode():
… print_r(json_decode($encoded, true)); // Здесь мы декоридируем закодированные JSON-данные.
// Второй параметр этой функции надо ставить если декодированные данные были возращены в виде массиве.
?>
Вывод будет в виде данных об массиве:
Array
(
[firstName] => Mike
[lastName] => Freeman
[job] => Web-developer
[contactData] => Array
(
[phoneNumber] => 3001300

PHP: Junior Kit
226
[e-mail] => mikefree@cool-app.com
)
)
Это всего лишь данные об массиве. Только что вы выучили две функции которые позволяют кодировать и декодировать JSON данные.
Эти функции играют важную роль, когда мы будем отправлять или получать данные в формате JSON. А теперь давайте поработаем с Star
Wars API. Star Wars API - это веб-сайт, который позволяет обучиться работать с JSON на простых практических примерах. Данные которые вы будете получать от Star Wars API это например информация об героях фильма, планетах которые были показаны в фильме и т.п.
То есть Star Wars API это по сути просто база данных об этом чудесном фильме, и суть в том чтобы на примере данных которые там есть научиться работать с JSON, а также немного привыкнуть к работе с
API. Вы можете прямо сейчас перейти на веб-сайт Star Wars API по адресу: https://swapi.co. И прямо на веб-сайте вы сможете уже сделать запросы на чтобы протестировать API. Вот, как я получил данные
C-3PO на swapi.io:

PHP: Junior Kit
227
-
Рис. 36 - Пример вывода результата после запроса на swapi.io
Сначала я ввел в адресной строке объект который я хочу получить. У меня это была группа people, после чего я указал номер героя об котором я хочу получить информацию. Дальше я нажал на кнопку “request”, после чего получил данные в формате JSON. Если, например, вы хотите получить данные об четвертом герое фильма, то тогда надо просто указать его цифру, например вот так people/4/.
Можете также зайти в документацию SWAPI, и посмотреть какой элемент в массиве данных за что отвечает. Сразу ясно что когда мы делаем запрос на получение данных об каком то персонаже, то например элемент name будет отвечать за имя персонажа. А теперь давайте поговорим о том, как можно делать запросы на получение данных с помощью
PHP.
Есть функция имеющая название file_get_contents()
, данная функция, позволяет получит содержимое страницу определенного сайта и отобразить через

PHP: Junior Kit
228
написанный РНР скрипт. Вот пример получения содержимого страницы
SWAPI с помощью использования функции file_get_contents():
$url = file_get_contents("https://swapi.co"); echo $url;
?>
После выполнения данного скрипта вы получите содержимое главной страницы SWAPI через ваш скрипт. Функция вообще имеет 5 параметров. Но нас будет интересовать именно те параметры которые позволяют доставать данные.
С помощью третьего параметра функции мы можем определить параметры запроса и сделать тем самым запрос более динамическим.
Например, вот скрипт где есть переменная $context, с помощью которой мы как раз и задаем больше параметров для запроса, что позволяет его сделать более динамичным как я уже и говорил:
$options = array(
"http" => array(
"method" => "GET",
"header" => "Accept-language: en\r\n"
)
);
$context = stream_context_create($options);
$file = file_get_contents("https://swapi.co", false, $context);
?>
Здесь, в этом примере мы указали параметры заголовка для HTTP запроса. Об том что это такое мы уже с вами говорили. В переменной
$context мы создаем поток данных, после этого с помощью переменной $file мы достаем содержимое главной страницы SWAPI только уже с заданными нами параметрами для заголовков.

PHP: Junior Kit
229
Второй параметр функции file_get_contents() может иметь только одно из двух логических значений. Второй параметр позволяет делать поиск файла, в нашем случае мы ничего не ищем, и поэтому ставим значение, которое равно ложи. Это как раз один из способов получения данных. А теперь давайте получим данные об одном из героев в формате JSON. Поэтому для этого мы возьмем такие параметры для запроса:
$url = "https://swapi.co/people/4/";
$options = array(
"header" => "Content-Type: application/json");
);
$context = stream_context_create("http" =>
$options); echo file_get_contents($url, false, $context);
?>
Обратите внимание на то что мы указали что мы хотим получить
1   ...   6   7   8   9   10   11   12   13   14


написать администратору сайта