1 Востаннє редагувалося Monolith (22.12.2016 20:51:20)

Тема: Очищення масиву $_POST[]

Зараз пишу скрипт коментарів для блогу. Все працює. Додає до бд, виводить вже додані. Загалом ось код:

// для виведення успіху/помилок при надсиланні коментарів
$success = '';
$error_name = '';
$error_email = '';
$error_comment = '';
$error = false;

// $post_id перевіряється/присвоюється з адреси

if ( isset($_POST['send_comment']) ) {

            $name = '';
            $name = trim( $_POST['name'] );
            $name = strip_tags($name);
            $name = htmlspecialchars($name);
            $_SESSION['name'] = $name;

            $email = '';
            $email = trim( $_POST['email'] );
            $email = strip_tags($email);
            $email = htmlspecialchars($email);
            $_SESSION['email'] = $email;

            $comment = '';
            $comment = strip_tags($_POST['comment']);
            $comment = trim($comment);
            $comment = htmlspecialchars($comment);
            $_SESSION['comment'] = $comment;

            if ( $name == '' ) {
                $error_name = "Введіть ім'я!";
                $error = true;
            } else if ( strlen($name) > 25 ){
                $error_name = "Задовге ім'я!";
                $error = true;
            }

            if ( $email == '' ) {
                $error_email = "Введіть пошту!";
                $error = true;
            } else if ( !preg_match('/^[^@\s]+@([-a-z0-9]+\.)+[a-z]{2,}$/i', $email) ) {
                $error_email = "Введіть дійсну пошту!";
                $error = true;
            }

            if ( $comment == '' ) {
                $error_comment = "Введіть коментар!";
                $error = true;
            }

            if ( !$error ) {
                $name = mysqli_real_escape_string($link, $name);
                $email = mysqli_real_escape_string($link, $email);
                $email = mysqli_real_escape_string($link, $comment);

                $result = add_comment($link, $name, $email, $comment, $post_id);

                $success = '<p class="success">Коментар додано!</p>';

                 unset($_SESSION['name']);
                 unset($_SESSION['email']);
                 unset($_SESSION['comment']);
                session_destroy();

                header("Location: ".$_SERVER['REQUEST_URI']); // напрявляємо користувача на ту ж саму сторінку
            }

        }
<div class="send-comment post-box">
        <h4>Залиш відгук:</h4>
        <?php echo $success; ?>
        <form action="/simpleblog/post/<?php echo $post_id; ?>" method="post">

            <label><span class="strong">Ім'я</span>
                <input type="text" name="name" required placeholder="Ім'я" maxlength="25" value="<?php if (isset($_SESSION['name'])) echo $_SESSION['name']; ?>">
            </label>
            <p><span class="error"><?php echo $error_name; ?></span></p>

            <label><span class="strong">Пошта</span>
                <input type="email" name="email" required placeholder="Пошта" value="<?php if (isset($_SESSION['email'])) echo $_SESSION['email']; ?>">
            </label>
            <p><span class="error"><?php echo $error_email; ?></span></p>

            <label><span class="strong">Відгук</span>
                <textarea required placeholder="Відгук" name="comment"><?php if (isset($_SESSION['comment'])) echo $_SESSION['comment']; ?></textarea>
            </label>
            <p><span class="error"><?php echo $error_comment; ?></span></p>

            <input type="submit" name="send_comment">

        </form>
    </div>

Ніби все скинув. Загалом в мене після відсилання коментаря і перезавантаженні сторінки вискакувало таке:

https://pp.сайт-злодій/c836726/v836726466/28a75/3E3qcxelFsQ.jpg


Я розумію чому так. Але як правильно вирішити проблему не знаю. Додав на 65 рядку:

header("Location: ".$_SERVER['REQUEST_URI']);

Так, тепер немає цієї проблеми. Але так стираються змінні

$success = '';
$error_name = '';
$error_email = '';
$error_comment = '';

Як так бути? Полазив у гуглі і знайшов тільки один комент, що можна винести перевірку у окремий файл(зараз в мене все відсилається на той же, де можна додати коментар). Але в мене виходить та ж проблема: не можу зробити, щоб ті декілька змінних можна було з потрібними збереженими значеннями відправити і вивести на тій сторінці, де форма.

Хтось вже стикався з такою проблемою?

UPD Знайшов ось таке рішення: https://habrahabr.ru/post/149376/#comment_5050492
Але судячи з коментарів воно не найкраще. Як гадаєте?

Подякували: 221VOLT1

2 Востаннє редагувалося 221VOLT (22.12.2016 21:13:13)

Re: Очищення масиву $_POST[]

ще краще - використовувати ajax -
зручно та корисно, тільки не треба забувати про безпеку -- CSRFProtection

https://www.owasp.org/index.php/Cross-S … heat_Sheet

власне, це не тільки вирішить цю видиму мікро-проблему,
але і велику невидиму проблему безпеки --

наприклад, якщо ваша жертва залогінена в інтернет-банкінгу, де немає захисту CSRFProtection --
існує можливість від лиця жертви переслати собі фінанси, чи якісь інші дії - post-get запит вона виконає просто перейшовши по вашій ссилці в новій вкладці
(і це можливе навіть якщо заборонене завантаження сайта банкінгу в айфреймі)

власне, комент на хабрі - це першопочатковий варіант CSRFProtection , який потребує покращень

Подякували: Monolith1

3 Востаннє редагувалося Monolith (23.12.2016 16:21:05)

Re: Очищення масиву $_POST[]

Загалом по-шукавши ще в Інтернеті вирішив все-таки робити як було у тому коменті. Та й 221VOLT мені багато в чому допоміг. Ось рішення:

У формі додаємо:

<input type="hidden" name="token" value="<?php echo ( rand(10000, 99999) ); ?>">

І сама перевірка:

if ( isset($_POST['send_comment']) ) {
    // якщо користувач натиснув кнопку у формі, а не просто зайшов на сторінку

    if ( !($_POST['token'] == $_SESSION['lastToken']) ) {
        // якщо змінні(які отримують кожен раз унікальне значення) не однакові, тобто сторінку оновили

        $_SESSION['lastToken'] = $_POST['token'];
        // далі перевіряємо відправлені дані, вставляємо їх до бд

    }

}

Також видаляємо рядок

session_destroy();

щоб при успішному доданню коментаря до бд у нас не стиралася змінна $_SESSION['lastToken'].

UPD Тільки зараз помітив, що забув дещо:

if ( isset($_SESSION['lastToken']) && !($_POST['token'] == $_SESSION['lastToken']) )

на 4 рядку. Це, щоб не вискакувала помилка, що не існує змінної $_SESSION['lastToken'] при першому заході на сторінку.

4

Re: Очищення масиву $_POST[]

алго-ритмо :

  • перевірили чи був пост-запит

  • перевіряємо чи то не хацкер -- узяли з бази/памяті попередні збережені коди безпеки даного користувача

  • узяли з бази всі потрібні значення в залежності від попередньої перевірки

  • генеруємо і зберігаємо новий код безпеки, старий видаляємо

  • виводимо потрібну інформацію на сторінку

  • *не забути поставити видалення неактивних кодів - наприклад раз в годину, чи раз в день

загалом, для просто коментарів на сайті - з такою безпекою можна не паритись -
просто зберігаємо-додаємо новий коментар з допомогою ajax (і сторінка не проситиме перезагрузки і коментарі не вставлятимуться двічі)

Подякували: Monolith1

5

Re: Очищення масиву $_POST[]

@misha_bondar_2012 робіть редірект і все у вас буде добре ;)
Додалки комент - відправили на нову сторінку.

Подякували: 221VOLT1

6

Re: Очищення масиву $_POST[]

funivan написав:

@misha_bondar_2012 робіть редірект і все у вас буде добре ;)
Додалки комент - відправили на нову сторінку.

Тоді не зберігається значення зміних, які містять повідомлення про помилки/успіх. Як розберуся у Ajax, то напишу вже по-людські.  :-X

Подякували: 221VOLT1

7

Re: Очищення масиву $_POST[]

Тоді не зберігається значення зміних, які містять повідомлення про помилки/успіх. Як розберуся у Ajax, то напишу вже по-людські.  :-X

Якщо у вас помилка - ми не робимо редірект, а показуємо інформацію про помилку.
Якщо все ок - робимо редірект.
Наскільки я знаю це хороша практика ;)

Подякували: Monolith1