Openssl_encryption с подготовленными операторами

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

1. Является ли Openssl лучшей практикой шифрования php?

2. Как мне добавить openssl в свой код?

Мне сложно интегрировать openssl с моим подготовленным кодом оператора.

Мой код:

<?php
session_start();
require_once './config/config.php';
require_once 'includes/auth_validate.php';

//Only super admin is allowed to access this page
if ($_SESSION['admin_type'] !== 'super') {
    // show permission denied message
    echo 'Permission Denied';
    exit();
}

if ($_SERVER['REQUEST_METHOD'] == 'POST') 
{
    $admin_type = mysqli_real_escape_string($conn, $_POST['admin_type']);
    $position = mysqli_real_escape_string($conn, $_POST['position']);
    $first_name = mysqli_real_escape_string($conn, $_POST['first_name']);
    $last_name = mysqli_real_escape_string($conn, $_POST['last_name']);
    $user_name = mysqli_real_escape_string($conn, $_POST['user_name']);
    $email = mysqli_real_escape_string($conn, $_POST['email']);
    $phone_number = mysqli_real_escape_string($conn, $_POST['phone_number']);
    $passwd = mysqli_real_escape_string($conn, $_POST['passwd']);
    $about = mysqli_real_escape_string($conn, $_POST['about']);

    //Error handlers 
    //Check for empty fields 
    if (empty($admin_type) || empty($position) || empty($first_name) || empty($last_name) || empty($user_name) || empty($passwd)){
        $_SESSION['failure'] = "Admin was not created, missing imporant details!";
        header('location: admin_users');
        exit();
    } else {
        $sql = "SELECT * FROM admin_accounts WHERE user_name='$user_name'";
        $result = mysqli_query($conn, $sql);
        $resultCheck = mysqli_num_rows($result);

        if ($resultCheck > 0) {
            $_SESSION['failure'] = "Admin was not created, username already used!";
            header('location: admin_users');
            exit();    
        } else {
            //Hashing password 
            $hashedPasswd = password_hash($passwd, PASSWORD_DEFAULT); 

            //Insert the user into the database 
            $sql = "INSERT INTO admin_accounts (admin_type, position, first_name, last_name, user_name, email, phone_number, passwd, about) VALUES (?,?,?,?,?,?,?,?,?);";

            $stmt = mysqli_stmt_init($conn);
            if (!mysqli_stmt_prepare($stmt, $sql)) {
                echo "SQL Error";
            } else {
                mysqli_stmt_bind_param($stmt, "sssssssss", $admin_type, $position, $first_name, $last_name, $user_name, $email, $phone_number, $hashedPasswd, $about);
                mysqli_stmt_execute($stmt);
              {
                    $_SESSION['success'] = "Admin user added successfully!";
                    header('location: admin_users');
                    exit();
                }     
            }
        }
    }
}
$edit = false;

Пример Openssl_Encryption:

<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
    //store $cipher, $iv, and $tag for decryption later
    $original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
    echo $original_plaintext."\n";
}

Моя попытка шифрования только First_Name: (Это не работает, не влияет на базу данных)

<?php
session_start();
require_once './config/config.php';
require_once 'includes/auth_validate.php';

//ONLY SUPER ADMINS ARE ALLOWED TO ACCESS THIS PAGE 
if ($_SESSION['admin_type'] !== 'super') {
    // show permission denied message
    echo 'Permission Denied';
    exit();
}


if ($_SERVER['REQUEST_METHOD'] == 'POST') 
{
$admin_type = mysqli_real_escape_string($conn, $_POST['admin_type']);
$position = mysqli_real_escape_string($conn, $_POST['position']);
$first_name = mysqli_real_escape_string($conn, $_POST['first_name']);
$last_name = mysqli_real_escape_string($conn, $_POST['last_name']);
$user_name = mysqli_real_escape_string($conn, $_POST['user_name']);
$email = mysqli_real_escape_string($conn, $_POST['email']);
$phone_number = mysqli_real_escape_string($conn, $_POST['phone_number']);
$passwd = mysqli_real_escape_string($conn, $_POST['passwd']);
$about = mysqli_real_escape_string($conn, $_POST['about']);
    
    //EROOR HANDLERS
    //CHECK FOR EMPTY FIELDS 
    if (empty($admin_type) || empty($position) || empty($first_name) || empty($last_name) || empty($user_name) || empty($passwd)){
        $_SESSION['failure'] = "Admin was not created, missing imporant details!";
        header('location: admin_users');
        exit();
    } else {
                $sql = "SELECT * FROM admin_accounts WHERE user_name='$user_name'";
                $result = mysqli_query($conn, $sql);
                $resultCheck = mysqli_num_rows($result);
                
                if ($resultCheck > 0) {
                    $_SESSION['failure'] = "Admin was not created, username already used!";
                    header('location: admin_users');
                    exit();    
                } else {
                    //HASHING PASSWORD 
                    $hashedPasswd = password_hash($passwd, PASSWORD_DEFAULT); 
                    
                    //INSERT THE USER INTO THE DATABASE  
                    $sql = "INSERT INTO admin_accounts (admin_type, position, first_name, last_name, user_name, email, phone_number, passwd, about) VALUES (?,?,?,?,?,?,?,?,?);";

                    $stmt = mysqli_stmt_init($conn);
                    if (!mysqli_stmt_prepare($stmt, $sql)) {
                        echo "SQL Error";
                    } else {
                        mysqli_stmt_bind_param($stmt, "sssssssss", $admin_type, $position, $first_name, $last_name, $user_name, $email, $phone_number, $hashedPasswd, $about);
                        mysqli_stmt_execute($stmt);
                        
                        {
                            $first_name = mysqli_real_escape_string($conn, $_POST['first_name']);
                            $cipher = "aes-128-gcm";
                            if (in_array($cipher, openssl_get_cipher_methods()))
                            {
                                $ivlen = openssl_cipher_iv_length($cipher);
                                $iv = openssl_random_pseudo_bytes($ivlen);
                                $ciphertext = openssl_encrypt($first_name, $cipher, $key, $options=0, $iv, $tag);
                            }

                        }
                        
                      {
                            $_SESSION['success'] = "Admin user added successfully!";
                            header('location: admin_users');
                            exit();
                        }     
                    }

                }
                
            }
            
        }
               

$edit = false;

?>

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

ArtisticPhoenix 10.08.2018 17:29

@ArtisticPhoenix я не уверен, что ты говоришь в последнем предложении

user10078643 10.08.2018 17:32

К вопросу !, i'm having a bit of difficulty integrating openssl with my prepared statement code Что вы пробовали, я не вижу никаких попыток его использовать, кроме того, он даже не заключен в функцию. Что вам нужно будет сделать, чтобы повторно использовать код ....

ArtisticPhoenix 10.08.2018 17:32

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

ArtisticPhoenix 10.08.2018 17:33

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

user10078643 10.08.2018 17:34

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

ArtisticPhoenix 10.08.2018 17:36

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

user10078643 10.08.2018 17:38

В качестве примечания: вам также следует сделать свой первый поисковый запрос по user_name также подготовленным оператором. Как и сейчас, если только не у тебя все правильно, он все еще может быть уязвим для атак с использованием sql-инъекций. Просто безопаснее (меньше догадок) идти вперед и делать любой запрос, используя вводимые пользователем данные, как они были подготовлены.

IncredibleHat 10.08.2018 19:03
0
8
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

. I'd like to add an extra layer of protection by encrypting all data (except for password and username).

Как я уже упоминал в своих комментариях, практический аспект этого заключается в том, что вы, вероятно, не сможете искать какие-либо данные, которые вы зашифровываете с помощью AES, потому что AES возвращает другое значение каждый раз, когда вы что-то шифруете. Это хорошо, но делает поиск практически невозможным. Вы можете сделать что-то вроде того, что в дополнение к AES, создайте хэш, используя что-то вроде SHA256, хэши действительно возвращают одно и то же значение каждый раз (но они односторонние, без дешифрования). Таким образом, с хешем, хранящимся в БД, вы можете хешировать свои данные и искать хеш в ранее сохраненной БД. Недостатком этого, помимо дополнительной сложности, является то, что это обычно ослабляет ваше шифрование. Если они не могут атаковать AES, они могут, например, попытаться перебрать HASH.

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

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

       $data = ['foo'=>'bar', 'stuff'=>'otherthing'];

       $json = json_encode($data); //'{"foo":"bar", "stuff":"otherthing"}'

       $encrypted = AESencrypt($json); //or whatever the function is

Затем вы берете $encrypted и сохраняете его в поле под названием secure или что-то в этом роде.

И последнее: я настоятельно рекомендую использовать PHPSecLib2.0.

https://github.com/phpseclib/phpseclib

Он не только предоставит вам лучший API, поскольку он полностью объектно-ориентирован, но также имеет встроенную имплантацию SSL (хотя установка расширения open_ssl сделает это быстрее).

С PHPseclib это все, что вам нужно сделать

function encryptAES($key, $plaintext){
    $Cipher = new AES(AES::MODE_CBC);
    $Cipher->setKey($key);    

    //create the IV
    $iv = Random::string($Cipher->getBlockLength() >> 3);
    $Cipher->setIV($iv);

    //encrypt and combine (you have to know the IV to decode. this is the typical way it's done) the IV is like a salt.
    $encrypted = $iv_base64 . base64_encode($Cipher->encrypt($plaintext));
    return $encrypted;
}


function decryptAES($key, $plaintext){
    $Cipher = new AES(AES::MODE_CBC);
    $Cipher->setKey($key);
    //find and decode the iv
    $iv = base64_decode(substr($ciphertext, 0, 22) . '==');

    //remove the iv from ciphertext
    $encrypted = substr($ciphertext, 22);

    $Cipher->setIV($iv);

    $decrypted = $Cipher->decrypt(base64_decode($encrypted));
    return $decrypted;
}

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

ПРИМЕЧАНИЕ

Одно слово предостережения, и это справедливо для любого симметричного двустороннего шифрования (шифрование, использующее 1 ключ вместо публичных / частных пар). Разве что его безопасность настолько же безопасна, насколько надежен ваш ключ для шифрования. Поскольку сервер должен знать этот KEY, если кто-то получит доступ к файловой системе и БД вашего сервера, есть большая вероятность, что он сможет найти ключ, который вы использовали для шифрования. Это серьезно ограничивает "реальную" безопасность, которую это предлагает. Это не значит, что этого делать не стоит, просто вы должны понимать ограничения и осознавать риски при работе с данными, которые необходимо зашифровать. Например, я бы не стал использовать AES на сервере для хранения кредитных карт или других данных типа PCI.

По сути, это перекладывает ответственность за безопасность с базы данных на сервер, на котором находится код. Необработанные данные бесполезны, потому что они зашифрованы, но код должен иметь доступ к KEY, и если у кого-то есть доступ к нему, они могут аналогичным образом расшифровать данные. Есть вещи, которые вы можете сделать, чтобы защитить сервер от атак (DMZ и т. д.), Но это выходит за рамки вопроса.

Ваше здоровье.

Ах хорошо, большое спасибо за вашу помощь. Чтобы я полностью понял, я не смогу использовать функцию поиска даже после того, как расшифрую данные?

user10078643 10.08.2018 17:54

Что ж, чтобы расшифровать данные, вы должны их уже найти. Это проблема. И непрактично расшифровать всю БД, затем выполнить поиск и повторно зашифровать все это. Это может быть полезно для сохранения конфиденциальной информации.

ArtisticPhoenix 10.08.2018 18:17

Другие вопросы по теме