URL-кодирование и фильтрация устраняют проблемы с выводом

Я пытаюсь понять, почему дезинфицированная строка будет выводиться иначе, чем недезинфицированная строка при кодировании URL.

Я не знаю, как это называется, но я искал URL-кодирование и очистку и пробовал Google, но не могу найти никакого объяснения.

Я обнаружил это случайно после публикации видео, проблема в том, что я вставляю заголовки в базу данных, извлекаю их и создаю с ними URL.

Пример URL (который не работает из-за проблемы)

localhost/proviin/video/kojima%26%2339%3Bs+cancelled+masterpiece+-+investigating+silent+hills/16

Я сделал тест на одной странице, чтобы проверить, что происходит и поведение, как вы можете видеть ниже.

Каким должен быть результат (но это не очищено):

$title = "Kojima's Cancelled Masterpiece - Investigating Silent Hills";
echo $title;
echo "<br>";
echo urlencode($title);

Выходы: (что будет работать в URL)

  • Отмененный шедевр Кодзимы — расследование Silent Hills
  • Кодзима%27s+Отменено+Шедевр+-+Расследование+Silent+Hills

Как это

$title = sanitize("Kojima's Cancelled Masterpiece - Investigating Silent Hills", "str");
echo $title;
echo "<br>";
echo urlencode($title);

Выходы: (который не работает в URL-адресе, но дезинфицируется)

  • Отмененный шедевр Кодзимы — расследование Silent Hills

  • Кодзима%26%2339%3Bs+Отменено+Шедевр+-+Расследование+Silent+Hills

Функция очистки

function sanitize($item, $type) {
    switch ($type) {
        case "str":
            return filter_var($item, FILTER_SANITIZE_STRING);
            break;
        case "mail":
            return filter_var($item, FILTER_SANITIZE_EMAIL);
            break;
        case "url":
            return filter_var($item, FILTER_SANITIZE_URL);
            break;
        case "int":
            return filter_var($item, FILTER_SANITIZE_NUMBER_INT);
            break;
        case "float":
            return filter_var($item, FILTER_SANITIZE_NUMBER_FLOAT);
            break;
        default:
            return false;
    }
}

Насколько я знаю:

Вы дезинфицируете данные перед вставкой в ​​базу данных.

Вы экранируете (htmlspecialchars), когда повторяете

Но почему очищенные строки выводятся по-разному при использовании urlencode() ?

Если это нормальное поведение, то как мне дезинфицировать строки перед их вставкой в ​​таблицу базы данных и использовать их в URL-адресе с urlencode() ?


person ii iml0sto1    schedule 23.01.2019    source источник
comment
Никогда, никогда, НИКОГДА не дезинфицируйте что-либо перед помещением в БД. Вы никогда не знаете, какой носитель вывода должен будет отображать эти данные, поэтому, если вы очистите его для использования в <a href="DATA_HERE">, вы сойдете с ума, пытаясь сделать так, чтобы он выглядел правильно для <div>DATA_HERE</div>   -  person MonkeyZeus    schedule 23.01.2019
comment
О, боже мой, разве я не должен дезинфицировать его, прежде чем помещать его в базу данных? :o Разве это не работает так: Перед вставкой: Sanitize При показе пользователю: escape (и т.д. htmlspecialcharts) ?   -  person ii iml0sto1    schedule 23.01.2019
comment
Я не согласен с @MonkeyZeus, если мы не проведем санитарную обработку, страница будет уязвима для постоянных XSS и SQL-инъекций.   -  person Vinay Sheoran    schedule 23.01.2019
comment
вы должны дезинфицировать ввод, а затем сохранять в БД и дезинфицировать при его выводе.   -  person Vinay Sheoran    schedule 23.01.2019
comment
@VinaySheoran я так и думал? дезинфицировать при вводе в базу, экранировать (htmlspecialchars?) при выводе данных из базы? Но я все еще не понимаю, что мне делать с вопросом выше.   -  person ii iml0sto1    schedule 23.01.2019
comment
@VinaySheoran Вы должны избегать вывода, чтобы предотвратить XSS, а не дезинфицировать ввод. Внедрение SQL обходится с помощью подготовленных операторов или экранирования данных с помощью функций mysqli.   -  person nickdnk    schedule 23.01.2019


Ответы (3)


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

Так что нет, вам не нужно дезинфицировать ваши данные, прежде чем вставлять их в базу данных. Вам нужно экранировать его, используя подготовленные операторы, чтобы он возвращался таким же образом при возврате из базы данных, готовый к тому, чтобы urlencode() или htmlentities() творили свое волшебство. Если вам не нужны данные, хранящиеся определенным образом, в этом случае preg_replace, вероятно, лучше.

Кроме того, имейте в виду, что пользовательский ввод также не должен быть unserialized() по той же самой причине: http://php.net/manual/en/function.unserialize.php

person nickdnk    schedule 23.01.2019

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

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

person Andrew Shaban    schedule 23.01.2019

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

/* urlsafe - Return a URL safe string */
public static function urlsafe($t)
{
    $t = strtolower($t);
    $t = preg_replace( "/[^a-z0-9]/", " ", $t);
    $t = trim($t);
    $t = preg_replace("/[ ]+/", "-", $t);
    return($t);
}
person Matthew Page    schedule 23.01.2019