03.08.2024

Шифрование имен полей формы Web-приложений

Vortex777

Интересующийся
Регистрация
27.06.2022
Сообщения
98
Реакции
0
Гарант продажи
0
Гарант покупки
0
Депозит
0 р
Большинство спамерских программ-авторассыльщико работают по следущему принципу:
1. В базу заносятся адрес скрипта, обрабатывающего сообщение, подаваемое на доску/форум/гостевую и т.д., а так-же названия полей в форме и их описание
2. Авторассыльщик отправляет запросы на адреса из базы с данными полей.

Идея заключается в том, чтобы динамически шифровать названия полей, из-за чего они не могут быть занесены в их базы, а если авторассыльщик и будет обращатся к скрипту напрямик, все равно ничего не добьется (единственное - это то, что он в логах безопасности пропишется, и больше ничего)

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

Инклюдный файл инициализации/реинициализации ключей (листинг "InitKeys.inc.php"):
Код:
<?php
$_SESSION['Keys[1]'] = rand(1000,9999);
$_SESSION['Keys[2]'] = rand(1000,9999);
$_SESSION['Keys[3]'] = rand(10,99);
$_SESSION['Keys[4]'] = rand(65,90);
?>
Количество ключей может быть любым (в пределах разумного), но 4 ключа думаю вполне хватит, т.к. подобрать их очень сложно (учитывая еще время доступа к серверу, которое всегда немного, но отличается, вследствии чего подобрать последовательность генерации практически невозможно)
Четвертый ключ нужен для того, чтобы имя переменной было правильным, но об этом пониже.

Исходник функции расширенного хеширования строки (имени поля формы)("Encrypt.inc.php"):
Код:
<?php
function EncryptField($Source)
{
$Source = chr($_SESSION['Keys[4]']).md5(crypt($_SESSION['Keys[1]'].$Source.$_SESSION['Keys[2]'],$_SESSION['Keys[3]']));
return $Source;
}
?>
$Source = chr($_SESSION['Keys[4]'])
Эта конструкция добавляет в начало сгенерированной строки символ латинского алфавита, чтобы не было такой ситуации, когда имя переменной начинается с цифры, что является неправильным именем переменной и могло бы вызвать ошибку времени исполнения
После обработки этой функцией строки, содержащей имя переменной формы, получается шифрованная необратимым способом строка (например, "U242908f3ba2cc1e35faac91c45de38fc")
Расшифровать ее очень сложно, т.к. ключи находятся на сервере и не передаются клиенту.

Теперь о применении этого метода:
Есть два способа обработки формы.
Первый - форму (например, файл "Form.php") обрабатывает другой скрипт (например, "Handler.php").
И второй - скрипт обработки включен в файл с формой (физически или же инклюдом внешнего файла)

Вначале первый способ.

Листинг страницы формы ("Form.php"):
Код:
<?php
session_start(); // Инициализация сессии
include_once("InitKeys.inc.php"); // Инициализация ключей (реинициализация при каждой перегузки страницы)
include_once("Encrypt.inc.php"); // Объявление функции хеширования
?>

<form action="Handler.php" method="POST">
<input type="text" name=<? echo '"'.EncryptField("Name").'"' ?>> // Именем поля формы будет хеш от строки "Name"
<input type="text" name=<? echo '"'.EncryptField("Message").'"' ?>> // Именем поля формы будет хеш от строки "Message"
<input type="submit">
</form>
Листинг обработчика ("Handler.php"):
Код:
<?php
session_start(); // Инициализация сессии
if (!isset($_SESSION['Keys[1]']))
{
// Ключи не были инициированы, что означает то, что было прямое обращение к скрипту обработчика.
// Здесь можно просто завершить работу скрипта, или сохранить в логах содержимое пост-массива, ип адрес, дату и т.д.
}
include_once("Encrypt.inc.php"); // Объявление функции хеширования
$DEC_N = EncryptField("Name"); // Находим хеш от строки "Name" при данном наборе ключей
$DEC_M = EncryptField("Message"); // Находим хеш от строки "Message" при данном наборе ключей
include("InitKeys.inc.php"); // Реинициализируем ключи, чтобы избежать повторного обращения к скрипту с теми же ключами, но в обход вызывающего скрипта Form.php
if ((!isset($_POST[$DEC_N])) OR (!isset($_POST[$DEC_M]))) // Проверяем, есть ли в пост-массиве переменные с найденными хешами
{
// Нет таких переменных (или одной из них). Это свидетельствует о двух ситуациях: Либо это уже не первое обращение к скрипту напрямик, либо просто кто-то несколько раз нажимает на кнопку отправки запроса на страницу "Form.php"
// Можно тоже либо просто завершить работу, либо ничего не делать ,т.е. не записывать сообщение в базу (а вдруг это просто пльзователи, которые нажали несколько раз на кнопку отправки запроса), либо заносим в лог.
}
else
{
// Данные пришли через форму, и можно их обрабатывать так, как надо, т.е. запрос прошел проверку
}
?>
Теперь второй способ (Форма и обработчик формы в одном файле)
Отличие этого способа от предыдущего в том, чтобы избежать двойной реинициализации ключей при отправке запроса

Листинг файла "FormAndHandler.php":
Код:
<?
session_start();
if ($_SERVER["REQUEST_METHOD"] != "POST") // Инициализируем ключи только в том случае, если не было запроса
include_once("InitKeys.inc.php");
include_once("Encrypt.inc.php");
?>
// Дальше идет содержимое страницы
...
...
// А тут идет форма
<form action="Handler.php" method="POST">
<input type="text" name=<? echo '"'.EncryptField("Name").'"' ?>>
<input type="text" name=<? echo '"'.EncryptField("Message").'"' ?>>
<input type="submit">
</form>
.... // Тоже все, что угодно...
// Тут обработчик формы (или инклюд на обработчик) (он может идти и в самом начале файла, кому как нравится)
<?
$DEC_N = EncryptField("Name"); // Находим хеш от строки "Name" при данном наборе ключей
$DEC_M = EncryptField("Message"); // Находим хеш от строки "Message" при данном наборе ключей
include("InitKeys.inc.php"); // Реинициализируем ключи
if ((!isset($_POST[$DEC_N])) OR (!isset($_POST[$DEC_M]))) // Проверяем, есть ли в пост-массиве переменные с найденными хешами
{
// Нет таких переменных (или одной из них).
// Можно тоже либо просто завершить работу, либо ничего не делать ,т.е. не записывать сообщение в базу, либо заносим в лог.
}
else
{
// Данные пришли через форму, и можно их обрабатывать так, как надо, т.е. запрос прошел проверку
}
?>
Теперь о уязвимости данного способа (а точнее о том, как его можно обойти): для этого нужно при каждом обращении парсить страницу и извлекать названия полей форм. Но во-первых, это накладно с точки зрения затрат времени и трафика, от чего спамеры не прийдут в восторг, и во-вторых, эту уязвимость тоже можно устранить.
 
Сверху