Статьи

Простые методы блокировки вашего сайта

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


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


  • Как генерировать случайные значения с помощью PHP
  • Генерация случайных паролей
  • Соляные пароли и аутентификация пользователя
  • Обфускация в PHP, обзор
  • Криптография в PHP и ее приложениях

Dictionary.com определяет рандомизацию как:

«-verb: упорядочивать или выбирать случайным образом, как в выборке или эксперименте, особенно для уменьшения смещения и помех, вызванных нерелевантными переменными; сделайте случайными».

Генерация случайных чисел определяется различными способами, однако вычислительным генераторам не хватает «истинной» случайности, наблюдаемой в природе или в электронном шуме (нечеткий, визжащий, черно-белый канал на телевидении). Эти вычисленные значения рассматриваются как псевдослучайные.

PHP предоставляет нам несколько различных способов создания случайных значений. Давайте посмотрим на некоторые из наиболее популярных функций.

1
2
3
4
5
6
<?php
rand(int $min, int $max);
mt_rand(int $min, int $max);
str_shuffle($str);
uniqid($prefix, more_entropy=);
?>

Две функции rand() и mt_rand() , вероятно, являются наиболее широко используемыми функциями для генерации набора случайных чисел в PHP. Функция rand() ; является более старым генератором и выходит из строя из-за mt_rand() ; который быстрее, надежнее и может обрабатывать более высокое максимальное целочисленное значение на некоторых платформах. Функция str_shuffle() делает именно то, что вы ожидаете, она перетасовывает переданную ей строку.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
//Examples of mt_rand() usage
print mt_rand();//default
     
        echo «<br />»;
     
print mt_rand(0, 20);//Outputs a random integer between 0 and 20
     
        echo «<br />»;
     
//Examples of rand() usage
     
print rand();//default
     
        echo «<br />»;
     
print rand(0, 25);//Outputs a random integer between 0 and 25
 
        echo «<br />»;
     
//Example of str_shuffle usage
     
$string = ‘abcefghijklmnopqrstuvwxyz’;
     
print str_shuffle($string);//shuffles $string
?>

Функции rand() и mt_rand() принимают два параметра, где $min — это наименьшее целое число для начала, а $max — наибольшее целое число для конца. Функция str_shuffle принимает один параметр — строку, str_shuffle мутацию строки. Он действует так же, как если бы вы тасовали колоду карт.

Пока mt_rand(); будет выдавать случайное целое число, а str_shuffle будет смешивать строку, функция, широко используемая для создания случайных уникальных значений, является uniqid() . Это создает префиксный уникальный идентификатор на основе текущего времени в микросекундах ( через php.net ). Использование этой функции полезно для создания токенов сеанса и даже ключей форм, как показано в разделе Защита форм с помощью ключей форм .

1
2
3
4
5
6
7
8
9
<?php
//Examples of uniqid() usage
     
print uniqid();//default
     
        echo «<br />»;
     
print uniqid(«NETTUTS», TRUE);//Adding an additional prefix and setting more_entropy to TRUE
?>

Функция uniqid() принимает два параметра: первый добавляет префикс к результатам, а второй, если он установлен в значение TRUE, добавляет дополнительную энтропию в конец возвращаемого значения.


В сети есть множество примеров, которые генерируют случайные пароли, и все отлично справляются с этим. «Но почему, — спросите вы, — нужно ли мне генерировать случайный пароль?» Ответ прост: вам не нужно полагаться на то, что конечный пользователь предоставит себе менее надежный пароль на ходу. Генерация случайных паролей очень полезна при регистрации пользователей или когда пользователь делает запрос, потому что он забыл свой пароль . Это обеспечивает надежный пароль в начале работы с пользователем на вашем веб-сайте или может сократить количество строк кода, когда пользователю необходимо снова получить доступ.

Давайте рассмотрим несколько примеров: Пример 1

01
02
03
04
05
06
07
08
09
10
11
<?php
 
//A simple function which will output a random password
function randompassword($count){
 
$pass = str_shuffle(‘abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@#%$*’);
 
return substr($pass,3,$count);//returns the password
 
}
?>

Этот пример str_shuffle строку с помощью str_shuffle и возвращает строку в пределах подсчитанного диапазона. Поэтому, если вы хотите сгенерировать 8-символьный пароль, вы должны передать 8 функции randompassword или randompassword (8) из вашего исходного кода.

Пример 2

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?php
 
//Another example to create a random password
function anorandpass($count) {
     
    $m_rand = mt_rand();
 
    $u_id = uniqid(«MNO!@#$%^&*=+XYZ», TRUE);//create a unique identifier with some extra prefix and extra entropy
     
    $combine = $m_rand .
     
    $new = str_shuffle($combine);//shuffle our string
             
    return substr($new, 2, $count);//return the password
}
     
print anorandpass(8);
 
?>

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

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


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


Опять же, это подпадает под меру «не зависящее от конечного пользователя, чтобы обеспечить себя простой безопасности». Пользователи обычно используют пароли, которые легко запомнить, и даже используют одни и те же пароли для нескольких веб-сайтов (я знаю, верно !?). Пароли, которые легко запомнить, — это, как правило, слова в словаре и другие виды значений (например, 12345, QWERTY). Как разработчики, мы часто смеемся над этой практикой, но мы не можем отрицать, что это просто так.

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


Вот таблица SQL, которую мы будем использовать.

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
/*db_config.php*/
 
//database configuration
$db_host =»localhost» ;
$db_name = «thedbname»;
$db_usr = «username»;
$db_pass = «password»;//your database password
 
//Establish a connection with MySQL and select the database to use
mysql_connect($db_host, $db_usr, $db_pass) or die(«MySQL Error: » . mysql_error());
mysql_select_db($db_name) or die(«MySQL Error: » . mysql_error());
?>

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
/*registration.php*/
 
//require our db_config.php file
require (‘db_config.php’);
 
//Check to see if the form has been submitted
if(!empty($_POST[‘username’]) && !empty($_POST[’email’]) && !empty($_POST[‘password’])) {
     
    //Escape our posted inputs
    $username = mysql_real_escape_string($_POST[‘username’]);
    $email = mysql_real_escape_string($_POST[’email’]);
    $password = mysql_real_escape_string($_POST[‘password’]);
     
    //generate a strong unique salt
    $salt_gen = uniqid(mt_rand());
     
    //Combine email, the password and the salt together
    $combine = $email .
     
    //md5 hash the combined password * Note: md5 is only used in this scenario as an example
    $newpassword = md5($combine);
     
    //insert the values into the database
    $registerquery = mysql_query(«INSERT INTO users (usr_name, usr_pass, usr_email, usr_salt) VALUES (‘».$username.»‘, ‘».$newpassword.»‘, ‘».$email.»‘, ‘».$salt_gen.»‘)») or die(«MySQL Error: «.mysql_error());
     
    //let the user know of success or failure
    if ($registerquery) {
        echo ‘<h1>Success</h1>’;
    } else {
        echo ‘<h1>Failure</h1>’;
    }
}
?>

Давайте рассмотрим код PHP. Для простоты мы включили наш файл конфигурации базы данных. Далее PHP проверяет, была ли отправлена ​​форма HTML, проверяя, не являются ли переменные $_POST пустыми. Если они не пусты, сценарий переходит к удалению от пользователя опубликованных данных формы, подготавливая их для вставки в базу данных. Затем мы генерируем простую соль, используя uniqid() и mt_rand() и сохраняя ее в переменной $salt_gen . Чтобы засолить наш пароль, мы объединяем $ password, затем соль. Следующий шаг — одностороннее хеширование объединенных переменных с помощью md5.

«Но подождите! Вы также добавили электронную почту пользователей в начале пароля и солевой комбо!» Ага! Я сделал это потому, что, если злоумышленник каким-то образом получает доступ к моей базе данных, и соль, единственный способ, которым злоумышленник узнает наверняка, что адрес электронной почты используется при хешировании пароля, — это если он имеет доступ к исходный код. Насколько случайным и уникальным является адрес электронной почты?

Чтобы завершить оставшуюся часть кода PHP, мы вставляем наши переменные в таблицу базы данных в соответствующие поля и даем пользователю обратную связь об успехе или неудаче. Теперь на остальной части регистрационного файла, HTML

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
 
<head>
 
</head>
 
<body>
 
<form action=»» method=»post»>
    <label for=»username»>Enter a Username</label>
    <input type=»text» name=»username» /><br />
     
    <label for=»email»>Enter your Email</label>
    <input type=»text» name=»email» /><br />
     
    <label for=»password»>Enter a Password</label>
    <input type=»password» name=»password» /><br />
     
    <input type=»submit» name=»submit» value=»Submit» />
</form>
 
</body>
 
</html>

Здесь мы создаем простую HTML-форму, которая будет собирать имя пользователя, адрес электронной почты и пароль от пользователя. Ничего особенного здесь.


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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
/*login.php*/
 
//require our db_config.php file
require (‘db_config.php’);
 
//Check to see if the form has been submitted
if(!empty($_POST[‘username’]) && !empty($_POST[‘password’])) {
     
    //Escape our posted inputs
    $username = mysql_real_escape_string($_POST[‘username’]);
    $password = mysql_real_escape_string($_POST[‘password’]);
     
    //Grab the row associated with the username from the form
    $grab_row = mysql_query(«SELECT * FROM users WHERE usr_name = ‘».$username.»‘») or die («MySQL Error: «.mysql_error());
     
    //If only one row was retrieved
    if (mysql_num_rows($grab_row) == 1) {
         
        //create an array from the row fields
        $row = mysql_fetch_array($grab_row);
         
        //store the users salt in a var
        $salt = $row[‘usr_salt’];
         
        //store the users email in a var
        $email = $row[‘usr_email’];
         
        //recombine the variables email, password, and the salt
        $combine = $email .
         
        //re-hash the combined variables Note:md5 is only used in this scenario as an example
        $auth_pass = md5($combine);
         
        //check the database again for the row associated with the username and the rehashed password
        $checklogin = mysql_query(«SELECT * FROM users WHERE usr_name = ‘».$username.»‘ AND usr_pass = ‘».$auth_pass.»‘») or die(«MySQL Error: «.mysql_error());
         
        //if only one row is retrieved output success or failure to the user
        if(mysql_num_rows($checklogin) == 1) {
            echo ‘<h1>Yippie, we are authenticated!</h1>’;
        } else {
            echo ‘<h1>Oh no, we are not authenticated!</h1>’;
        }
    } else {
        echo ‘<h1>Oh no, we are not in the database!</h1>’;
    }
}
?>

В основном то, что мы делаем в файле login.php, — это использование переданных переменных формы, получение строки таблицы, связанной с именем пользователя, и восстановление пароля из элементов в базе данных, с которой он был создан (электронная почта, передача, соль) и перефразирование их. , Затем мы снова проверяем базу данных на наличие имени пользователя и перефразированного значения пароля, чтобы найти совпадение, выводя пользователя в случае успеха или неудачи. Наконец, вот HTML:


Простое, но сложное определение обфускации (используйте версию, содержащуюся в исходном коде, если вы хотите запустить код):

1
<?php $a1c0_z2=’c’.$a91.’tion ‘;$a91=»a»;$vly_ti=»us».’ed’;$j1h_32_a=’ to’;$z1b_1=$a91.» «;$lz32i_4=»“O».»bfus»;$g1k0p=’que ‘;$lv83=»t».’ec’.’hni’;$lFa=’i’.’s ‘;if($z1b_1==$a91.» «)$rx_b_1=’a’;$glccUv=» complic».$rx_b_1.’te ‘;$xl1ttf=’code ‘;$zljal1=»in such a»;if($z1b_1==$a91.» «)$s1b_1=’a’;$p1x2 =» w».$s1b_1.»y «;$il_7x=’ ‘.$b1zE_.’t i’.$l1yes;$b1zE_=»i»;$l1yes=»s»;$nltotry_ws=’st’.$s1b_1.»n»;$yl5B_=’thαt ‘;$dlno=’ not ‘;$m1tomanythings=»under»;if($s1b_1==’a’)$bz_1=$s1b_1;$Ozaq=»d».$bz_1.»ble»»;echo base64_decode(«JiM4MjIwO09iZnVzY3Rpb24mIzgyMDE7aXMmIzgyMDE7YSYjODIwMTt0ZWNobmlxdWUmIzgyMDE7dXNlZCYjODIwMTt0byYjODIwMWNvbXBsaWNhdGUmIzgyMDE7Y29kZSYjODIwMTtpbiYjODIwMTtzdWNoJiM4MjAxO2EmIzgyMDE7d2F5JiM4MjAxO3RoJmFscGhhO3QmIzgyMDE7aSYjODIwMTt0JiM4MjAxO2kmIzgyMDE7bm90JiM4MjAxO3VuZGVyc3RhbmRhYmxlJnF1b3Q7»);?>

Как видите, этот код не предназначен для различения. Здесь нет отдельных имен переменных, нет комментариев, нет пробелов, нет отступов, нет определенного порядка, и все это в одной строке. Хотя мы не можем различить код, наши машины все еще знают, что это такое. Оно работает. Эта строка хаоса просто повторяет: «Обфускация — это метод, используемый для усложнения кода таким образом, что он непонятен». Да, я знаю об ошибках.

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


Это общий вопрос. Есть прежде всего два способа запутать ваш код. Во-первых, вы можете сделать это вручную. Написание обфусцированного кода занимает много времени. Пример, использованный в этой статье, занял некоторое время, чтобы написать из-за тех же самых причин, по которым вы сначала используете запутывание (отсутствие структуры, порядка и т. Д.), Это даже привело к некоторым грубым ошибкам, которые я даже не хотел выследить и исправить. Второй способ, которым вы можете запутать свой код, это купить программное обеспечение, которое сделает это за вас. Использование программы для обфускации кода тривиально и, конечно, стоит много времени. Некоторое программное обеспечение, которое утверждает, что запутывает ваш код, фактически шифрует и / или кодирует его таким образом, чтобы оно функционировало при рукопожатии. Часто вы найдете программное обеспечение, поставщик которого даже не гарантирует, что ваш код будет работать, когда он будет готов. Даже в этом примере я использовал простую функцию Base64 для кодирования построения выходных данных скрипта.


  • Всегда, всегда, держите чистую версию исходного кода для себя.
  • Чем более случайна ваша техника, тем лучше.
  • Устранить все пробелы, где это не нужно.
  • Кодировка символов печатными / повторяющимися символами и пробелами (т. Е. Цитаты, пробелы, апостропы, знаки переноса)
  • Чем сложнее код, тем лучше.
  • Не обращайте внимания на структуру, если только это не наносит ущерба работе кода (за исключением переменных мест до их вызова)
  • Не используйте различимые имена переменных, пространства имен или имена классов.
  • Чем меньше кода вы используете повторно, тем лучше
  • Не верь, что это надежно

Это действительно зависит от вашего плана. Особенно, если вы хотите продать свой PHP-скрипт (или любое программное обеспечение), вам нужно его лицензировать. Это будет одним из самых передовых способов защиты, чтобы помешать целевой аудитории программного обеспечения делать то, что они хотят. Яркий пример лицензирования можно увидеть в Envato Marketplace Wiki . Тем не менее, вы можете захотеть запутать некоторые или весь ваш код по любой причине. Однако из-за негативных запутываний, если вы действительно беспокоитесь о безопасности вашего исходного кода, возможно, стоит вместо этого использовать шифрование.


Wikipedia.com определяет криптографию как:

«Практика и изучение сокрытия информации».

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


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

SHA-1, 2 и 3

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?php
 
///One way hashing with SHA-1
 
$string = «Netuts is Awesome»;
 
$hash = sha1($string);
//or
$hash2 = hash(‘sha1’, $string);
 
echo $hash.»<br />»;
echo $hash2.»<br /><br />»;
 
//Will output: 42d2f15c3f92d28d7d58776e5d81b800f662cc6c
?>

В PHP SHA-2 вызывается в другом отношении и требует, чтобы PHP 5 был больше или равен 5.1.2. SHA-2 превосходит SHA-1 и может вызываться с разными размерами битов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<?php
$string_sha256 = «Nettuts is Awesome»;
$string_sha384 = «Nettuts is Awesome»;
$string_sha512 = «Nettuts is Awesome»;
 
$hash_sha256 = hash(‘sha256’, $string_sha256);
$hash_sha384 = hash(‘sha384’, $string_sha384);
$hash_sha512 = hash(‘sha512’, $string_sha512);
 
echo $hash_sha256.»<br />»;
echo $hash_sha384.»<br />»;
echo $hash_sha512.»<br />»;
 
/* Outputs repspectively:
sha256 : 09074adc0d70e15b88494643e29c2836e1ab94a21989691dec594cb0bd742ebc
sha384 : 8535470750df54a78701d4bfe0451f9799057a5bc101944a32480d2436e8b95440bce3bcab3f9ce107b0b92d9595ae32
sha512 : c2e6dce873a71800b862791e56b480b976bb26cd3136c02da510c3905caa49b7b9e9260549976e1e741cc93e4569a611f2030d3b7104c6c6c2ff9e6c9bf0946a
*/
 
?>

Хеш-функция вызывается хешем (алгоритм, строка); В новейших версиях PHP функцию hash () можно использовать для вызова любого одностороннего алгоритма хеширования, поддерживаемого PHP (т. Е. Md5, sha-1, haval, ghost). Если вы хотите увидеть список всех зарегистрированных алгоритмов хеширования, вы можете использовать:

1
2
3
4
<?php
//As of PHP5 >= 5.1.2
print_r(hash_algos());
?>

SHA-3 все еще разрабатывается и рассматривается для стандартизации. Национальный институт стандартов и технологий объявил конкурс на поиск подходящего кандидата для использования в качестве нового безопасного алгоритма хэширования, и заявки на участие в конкурсе были объявлены до 31 октября 2008 года. Довольно популярная запись под названием Skein имеет доступный модуль PHP. Вы можете скачать (хотя вы должны скомпилировать его самостоятельно). Skein разработан некоторыми известными в индустрии безопасности именами, такими как Брюс Шнайер, Нильс Фергюсон и Стефан Лакс. Официальный сайт Skein можно найти здесь .


Методы шифрования с симметричным ключом — это когда безопасность шифрования в основном находится в ключе, который разделяется между двумя точками, где данные шифруются и где данные дешифруются. Очень хороший пример того, как это может работать, был представлен в учебнике Кристиана Бейкова « Создание класса Crypter with PHP ».


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

1
2
3
4
5
6
7
8
<?php
$string_hmac = «Nettuts is Awesome»;
 
//hash_hmac(algorithm, string to hash, key)
$hmac = hash_hmac(‘sha1’, $string_hmac, ‘secret’);
 
echo $hmac.»<br />»;
?>

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