безопасность — недокументированная санация при загрузке файлов PHP

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

// basename() may prevent filesystem traversal attacks;
// further validation/sanitation of the filename may be appropriate
$name = basename($_FILES["pictures"]["name"][$key]);

Несмотря на это, я обнаружил, что по умолчанию имя файла уже очищено, когда оно поступает в скрипт PHP.

У меня есть доказательства того, что Apache получает вредоносное имя файла: filename = «../ file.png», в то время как PHP-скрипт вместо этого считывает очищенное имя в переменную $ _FILES.

Низкоуровневый дамп ввода Apache:

mod_dumpio: dumpio_in (data-HEAP):
--------------------------eb8b65b665870e02
Content-Disposition: form-data;
name="attachment";
filename="../file.png" ← [Malicious file name]
Content-Type: image/png

PHP скрипт

echo $_FILES['attachment']['name']; ← [File name already sanitised: 'file.png']

Я обнаружил такое поведение как в модуле Apache, так и в php-fpm при работе PHP с 5.5 до 7.2, и я должен сделать вывод, что интерпретатор PHP выполняет эту очистку перед передачей переменной в сценарий.

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

0

Решение

Вы хотите посмотреть на rfc1867.cКажется, это та часть, на которую вы ссылаетесь:

SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)

Из комментария видно, что базовое () используется, чтобы избавиться от ложных обратных слешей, которые на самом деле могут быть правильный (Я представляю, возможно «Hello\ World.txt«?). Но это основано на поведении IE и в комментарии говорится, что он может быть удален в будущем.

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

    /* The \ check should technically be needed for win32 systems only where
* it is a valid path separator. However, IE in all it's wisdom always sends
* the full path of the file on the user's filesystem, which means that unless
* the user does basename() they get a bogus file name. Until IE's user base drops
* to nill or problem is fixed this code must remain enabled for all systems. */

s = _basename(internal_encoding, filename TSRMLS_CC);
if (!s) {
s = filename;
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]