Очистка строк для создания их URL и именем файла безопасный?

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

До сих пор я придумал следующую функцию, которая я надеюсь, решает эту проблему и позволяет внешние данные UTF-8 также.

/**
 * Convert a string to the file/URL safe "slug" form
 *
 * @param string $string the string to clean
 * @param bool $is_filename TRUE will allow additional filename characters
 * @return string
 */
function sanitize($string = '', $is_filename = FALSE)
{
 // Replace all weird characters with dashes
 $string = preg_replace('/[^\w\-'. ($is_filename ? '~_\.' : ''). ']+/u', '-', $string);

 // Only allow one dash separator at a time (and make string lowercase)
 return mb_strtolower(preg_replace('/--+/u', '-', $string), 'UTF-8');
}

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

$is-filename позволяет некоторые дополнительные символы как временные файлы энергии

обновление: удаленный звездообразный символ, так как я не мог думать о допустимом использовании

134
задан Lightness Races with Monica 20 June 2011 в 11:45
поделиться

10 ответов

Некоторые наблюдения по поводу вашего решения:

  1. 'u' в конце вашего шаблона означает, что шаблон , а не текст, который он соответствует, будет интерпретироваться как UTF-8 (я полагаю, вы предположили последний?).
  2. \ w соответствует символу подчеркивания. Вы специально включаете его для файлов, что приводит к предположению, что они не нужны вам в URL-адресах, но в коде, в котором у вас есть URL-адреса, будет разрешено включать подчеркивание.
  3. Включение «чужого UTF-8», похоже, зависит от локали. Неясно, является ли это локалью сервера или клиента. Из документации PHP:

Символ «слова» - это любая буква, цифра или символ подчеркивания, то есть любой символ, который может быть частью «слова» Perl. Определение букв и цифр контролируется символьными таблицами PCRE и может варьироваться, если имеет место соответствие для конкретной локали. Например, в языковом стандарте «fr» (французский) некоторые коды символов больше 128 используются для букв с диакритическими знаками, и им соответствует \ w.

Создание заголовка

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

Итак, если бы я был вами, после нижнего регистра, я бы преобразовал любые «специальные» символы в их эквиваленты (например, é -> e) и заменил символы, отличные от [az], на «-», ограничившись запусками одного '-' как вы это сделали. Здесь есть реализация преобразования специальных символов: https://web.archive.org/web/20130208144021/http://neo22s.com / slug

Общая дезинфекция

OWASP имеет PHP-реализацию своего Enterprise Security API, которая, среди прочего, включает методы для безопасного кодирования и декодирования ввода и вывода в вашем приложении.

Интерфейс кодировщика предоставляет:

canonicalize (string $input, [bool $strict = true])
decodeFromBase64 (string $input)
decodeFromURL (string $input)
encodeForBase64 (string $input, [bool $wrap = false])
encodeForCSS (string $input)
encodeForHTML (string $input)
encodeForHTMLAttribute (string $input)
encodeForJavaScript (string $input)
encodeForOS (Codec $codec, string $input)
encodeForSQL (Codec $codec, string $input)
encodeForURL (string $input)
encodeForVBScript (string $input)
encodeForXML (string $input)
encodeForXMLAttribute (string $input)
encodeForXPath (string $input)

https://github.com/OWASP/PHP-ESAPI https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API

57
ответ дан 23 November 2019 в 23:55
поделиться
// CLEAN ILLEGAL CHARACTERS
function clean_filename($source_file)
{
    $search[] = " ";
    $search[] = "&";
    $search[] = "$";
    $search[] = ",";
    $search[] = "!";
    $search[] = "@";
    $search[] = "#";
    $search[] = "^";
    $search[] = "(";
    $search[] = ")";
    $search[] = "+";
    $search[] = "=";
    $search[] = "[";
    $search[] = "]";

    $replace[] = "_";
    $replace[] = "and";
    $replace[] = "S";
    $replace[] = "_";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";
    $replace[] = "";

    return str_replace($search,$replace,$source_file);

} 
-4
ответ дан 23 November 2019 в 23:55
поделиться

Попробуйте следующее:

function normal_chars($string)
{
    $string = htmlentities($string, ENT_QUOTES, 'UTF-8');
    $string = preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', $string);
    $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
    $string = preg_replace(array('~[^0-9a-z]~i', '~[ -]+~'), ' ', $string);

    return trim($string, ' -');
}

Examples:

echo normal_chars('Álix----_Ãxel!?!?'); // Alix Axel
echo normal_chars('áéíóúÁÉÍÓÚ'); // aeiouAEIOU
echo normal_chars('üÿÄËÏÖÜŸåÅ'); // uyAEIOUYaA

На основе выбранного ответа в этой теме: URL-адрес дружественного имени пользователя в PHP?

21
ответ дан 23 November 2019 в 23:55
поделиться

Я нашел эту большую функцию в коде Chyrp :

/**
 * Function: sanitize
 * Returns a sanitized string, typically for URLs.
 *
 * Parameters:
 *     $string - The string to sanitize.
 *     $force_lowercase - Force the string to lowercase?
 *     $anal - If set to *true*, will remove all non-alphanumeric characters.
 */
function sanitize($string, $force_lowercase = true, $anal = false) {
    $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
                   "}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
                   "—", "–", ",", "<", ".", ">", "/", "?");
    $clean = trim(str_replace($strip, "", strip_tags($string)));
    $clean = preg_replace('/\s+/', "-", $clean);
    $clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
    return ($force_lowercase) ?
        (function_exists('mb_strtolower')) ?
            mb_strtolower($clean, 'UTF-8') :
            strtolower($clean) :
        $clean;
}

и эту в wordpress код

/**
 * Sanitizes a filename replacing whitespace with dashes
 *
 * Removes special characters that are illegal in filenames on certain
 * operating systems and special characters requiring special escaping
 * to manipulate at the command line. Replaces spaces and consecutive
 * dashes with a single dash. Trim period, dash and underscore from beginning
 * and end of filename.
 *
 * @since 2.1.0
 *
 * @param string $filename The filename to be sanitized
 * @return string The sanitized filename
 */
function sanitize_file_name( $filename ) {
    $filename_raw = $filename;
    $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}");
    $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
    $filename = str_replace($special_chars, '', $filename);
    $filename = preg_replace('/[\s-]+/', '-', $filename);
    $filename = trim($filename, '.-_');
    return apply_filters('sanitize_file_name', $filename, $filename_raw);
}

Обновление, сентябрь 2012 г.

Аликс Аксель проделал невероятную работу в этой области. Его phunction framework включает в себя несколько отличных текстовых фильтров и преобразований.

87
ответ дан 23 November 2019 в 23:55
поделиться

Я не думаю, что иметь список удаляемых символов безопасно. Я бы предпочел использовать следующее:

Для имен файлов: используйте внутренний идентификатор или хэш содержимого файла. Сохраните название документа в базе данных. Таким образом, вы можете сохранить исходное имя файла и при этом найти файл.

Для параметров URL: используйте urlencode () для кодирования любых специальных символов.

4
ответ дан 23 November 2019 в 23:55
поделиться

Я всегда думал, что Кохана неплохо справился с этим .

public static function title($title, $separator = '-', $ascii_only = FALSE)
{
if ($ascii_only === TRUE)
{
// Transliterate non-ASCII characters
$title = UTF8::transliterate_to_ascii($title);

// Remove all characters that are not the separator, a-z, 0-9, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'a-z0-9\s]+!', '', strtolower($title));
}
else
{
// Remove all characters that are not the separator, letters, numbers, or whitespace
$title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', UTF8::strtolower($title));
}

// Replace all separator characters and whitespace by a single separator
$title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);

// Trim separators from the beginning and end
return trim($title, $separator);
}

Удобный UTF8 :: transliterate_to_ascii () будет преобразовывать такие вещи, как ñ => n.

Конечно, вы можете заменить другие UTF8 :: * функциями mb_ *.

11
ответ дан 23 November 2019 в 23:55
поделиться

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

3
ответ дан 23 November 2019 в 23:55
поделиться

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

Используя OWASP ESAPI, эти имена могут быть сгенерированы следующим образом:

$userFilename   = ESAPI::getEncoder()->canonicalize($input_string);
$safeFilename   = ESAPI::getRandomizer()->getRandomFilename();

Вы можете добавить метку времени к $ safeFilename, чтобы гарантировать уникальность случайно сгенерированного имени файла, даже не проверяя существующий файл.

С точки зрения кодирования для URL и снова с использованием ESAPI:

$safeForURL     = ESAPI::getEncoder()->encodeForURL($input_string);

Этот метод выполняет канонизацию перед кодированием строки и обрабатывает все кодировки символов.

5
ответ дан 23 November 2019 в 23:55
поделиться

почему бы просто не использовать php urlencode ? он заменяет "опасные" символы их шестнадцатеричным представлением для URL-адресов (например, % 20 вместо пробела)

2
ответ дан 23 November 2019 в 23:55
поделиться

Это должно сделать ваши имена файлов безопасными...

$string = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $string);

и более глубокое решение для этого:

// Remove special accented characters - ie. sí.
$clean_name = strtr($string, array('Š' => 'S','Ž' => 'Z','š' => 's','ž' => 'z','Ÿ' => 'Y','À' => 'A','Á' => 'A','Â' => 'A','Ã' => 'A','Ä' => 'A','Å' => 'A','Ç' => 'C','È' => 'E','É' => 'E','Ê' => 'E','Ë' => 'E','Ì' => 'I','Í' => 'I','Î' => 'I','Ï' => 'I','Ñ' => 'N','Ò' => 'O','Ó' => 'O','Ô' => 'O','Õ' => 'O','Ö' => 'O','Ø' => 'O','Ù' => 'U','Ú' => 'U','Û' => 'U','Ü' => 'U','Ý' => 'Y','à' => 'a','á' => 'a','â' => 'a','ã' => 'a','ä' => 'a','å' => 'a','ç' => 'c','è' => 'e','é' => 'e','ê' => 'e','ë' => 'e','ì' => 'i','í' => 'i','î' => 'i','ï' => 'i','ñ' => 'n','ò' => 'o','ó' => 'o','ô' => 'o','õ' => 'o','ö' => 'o','ø' => 'o','ù' => 'u','ú' => 'u','û' => 'u','ü' => 'u','ý' => 'y','ÿ' => 'y'));
$clean_name = strtr($clean_name, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u'));

$clean_name = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $clean_name);

Это предполагает, что вы хотите точку в имени файла. Если вы хотите перевести его в нижний регистр, просто используйте

$clean_name = strtolower($clean_name);

для последней строки.

30
ответ дан 23 November 2019 в 23:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: