Как избежать угроз безопасности UNLINK в PHP?

Я использую UNLINK с PHP и AJAX. Я знаю, что таким образом очень опасно, потому что каждый может удалить любые файлы. Но мне нужно использовать AJAX, потому что я не могу перезагрузить страницу, когда удаляю файлы.

Итак, как мне разрешить удаление файла только тому пользователю, которому он принадлежит?

Пожалуйста, дайте мне знать и другие вещи, если вы думаете, что я делаю здесь что-то неправильно или что-то еще, что вы имеете в виду, и вы думаете, что это будет полезно :)

Мой код PHP:


<?php

    $photo_id       = $_GET['photo_id'];
    $thumbnail_id   = $_GET['thumbnail_id'];    

    function deletePhotos($id){
        return unlink($id);
    }

    if(isset($photo_id)){
        deletePhotos($photo_id);
    }
    if(isset($thumbnail_id)){
        deletePhotos($thumbnail_id);
    }


 ?>

Мой код AJAX:


function deletePhoto(photo, thumbnail){

        var photos = encodeURIComponent(photo);
        var thumbnails = encodeURIComponent(thumbnail);

        if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
          xmlhttp=new XMLHttpRequest();
        } else {// code for IE6, IE5
          xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }

        xmlhttp.onreadystatechange=function() {
            if (xmlhttp.readyState==4 && xmlhttp.status==200) {
                document.getElementById("media").innerHTML=xmlhttp.responseText;
            }
        }
        xmlhttp.open("GET", "http://192.168.2.104/images/users/delete_photo.php?photo_id="+photos+"&thumbnail_id="+thumbnails, true);
        xmlhttp.send();
    }

person Adam Halasz    schedule 05.08.2010    source источник
comment
AJAX не имеет ничего общего с безопасностью. С точки зрения сервера AJAX-вызов ничем не отличается от обычного. Ваша проблема не в AJAX, а в отсутствии авторизации. Чем раньше вы это поймете, тем быстрее решите свою проблему.   -  person Your Common Sense    schedule 05.08.2010
comment
Привет @Кол. Shrapnel, я не думаю, что вы полностью правы, потому что без AJAX мне не нужно делать файл, к которому любой может получить доступ и может удалить что-либо с помощью GET-запроса. В противном случае я знаю, что проблема здесь с авторизацией, поэтому я задал этот вопрос So how should I do to allow to delete the file only for the user who owns it?   -  person Adam Halasz    schedule 05.08.2010
comment
как вы можете позволить пользователю удалить файл без такого скрипта?   -  person Your Common Sense    schedule 05.08.2010
comment
Не без такого скрипта а без GET.   -  person Adam Halasz    schedule 05.08.2010
comment
И что? думаете, что запрос POST не должен быть защищен? ржу не могу   -  person Your Common Sense    schedule 05.08.2010
comment
вы сказали I don't need to make a file. Пора задуматься, чувак :)   -  person Your Common Sense    schedule 05.08.2010


Ответы (7)


Вам нужно как-то аутентифицировать пользователя.

Ваш пользователь должен пройти аутентификацию с помощью имени пользователя и пароля.

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

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

person Wadih M.    schedule 05.08.2010
comment
Если вы имеете в виду вход в систему, то пользователь вошел в систему. Если я не разрешаю пользователям доступ к файлу, которые не вошли в систему, это немного лучше, но пользователи, которые вошли в систему, они все еще могут удалять файлы друг друга. - person Adam Halasz; 05.08.2010
comment
вот почему вам нужно сохранить право собственности на файл в другой таблице, и перед тем, как что-либо отменить, вы должны убедиться, что аутентифицированный пользователь является владельцем файла. - person Wadih M.; 05.08.2010
comment
единственный разумный ответ здесь. @CIRK послушайте этот комментарий выше. это единственное решение. Вы идете совершенно неправильным путем. AJAX не ваша проблема - person Your Common Sense; 05.08.2010
comment
Да, это логичный ответ, проблема с моим общим кодом в том, что на этом этапе я не отправляю никаких данных в базу данных, но я думаю, что смогу понять, поэтому я попробую. - person Adam Halasz; 05.08.2010
comment
@CIRK да, идеальное слово - логично. без сохранения информации о владельце файла вы не можете проверить владельца файла. Очень логично, не правда ли? - person Your Common Sense; 05.08.2010
comment
Привет, CIRK, потребуется аутентификация пользователя и хранение метаданных о праве собственности. В противном случае было бы невозможно определить владельца файла. - person Wadih M.; 05.08.2010
comment
Вадих, добавьте к имени пользователя знак @, как я. это сделает ваш комментарий личным и позволит им увидеть ваш комментарий в разделе новых ответов. - person Your Common Sense; 05.08.2010

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

просто что-то вроде

$photo_id = basename($_GET['photo_id'];)
$filename = $filebase.$_SESSION['user_id']."/".$photo_id;
if (file_exists($filename) unlink ($filename);
person Your Common Sense    schedule 05.08.2010

Ограничить отвязку от каталога с фотографиями. То есть не разрешайте .. в пути или проверяйте полный путь после выполнения realpath(). В противном случае пользователь может запросить delete_photo.php?photo_id=../../../../etc/passwd и сломать систему.

person Sjoerd    schedule 05.08.2010
comment
Если они кодируют '..' в другом наборе символов, это потенциально может пройти. Я читал об этом в прошлом. - person Wadih M.; 05.08.2010
comment
@Wadih да, но это был недостаток (я думаю, в Apache), который с тех пор был исправлен. - person Pekka; 05.08.2010
comment
Если php работает как root, я думаю, у вас большие проблемы. - person rook; 05.08.2010
comment
Действительно, поскольку PHP не является корневым, пример /etc/passwd преувеличен и на самом деле не работает. - person Sjoerd; 06.08.2010

В вашем PHP:

  • Убедитесь, что $_GET['photo_id'] и $_GET['thumbnail_id'] не содержат "../"
  • Также убедитесь, что вы добавили базовый путь к идентификатору.

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

Что касается владельца, вы должны хранить информацию о том, кому принадлежит какой файл, где-то на стороне сервера (например, MySql-DB). Затем вам следует обратиться к этому местоположению перед удалением файла.

person JochenJung    schedule 05.08.2010

Как сказал Вадих М. Вам необходимо аутентифицировать пользователя. Затем вы можете использовать это, чтобы сравнить «Владелец изображения» с «Пользователь, который в настоящее время входит в систему». Это даст вам всю необходимую безопасность.

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

person Anraiki    schedule 05.08.2010
comment
Идентификатор - это не число :D, это file_name с некоторыми уникальными вещами перед ними, что-то вроде efb03_orange.png. Проблема в том, что в этом разделе я еще ничего не отправлял в базу. Поэтому я не знаю, как проверить, является ли зарегистрированный пользователь пользователем, которому принадлежит файл. - person Adam Halasz; 05.08.2010
comment
Я думаю, что это нарушение соглашения об именах для var. Должно быть похоже на $imagePlaceholder. Я буду делать дальнейшие обновления в ответ на ваш комментарий. - person Anraiki; 05.08.2010
comment
Я просто заметил, что ... заставлять человека перепрыгивать через еще один обруч может не потребоваться после проверки владельца файла. - person Anraiki; 05.08.2010
comment
ЭТО ВЫШЕ - ОЧЕНЬ ОПАСНЫЙ ФРАГМЕНТ КОДА. потому что: люди могут поместить %00 в $_GET['photo'], и поскольку php не заботит 0 байт, но все базовые функции libc позволяют удалить связь с любым существующим файлом. Попробуйте это: <?php var_dump(file_exists("/etc/passwd\0foo.gif")); ?> так что я повторяю: просто поместите это в базу данных, если вы действительно не уверены, что исключили все возможные лазейки, что вы почти не можете сделать - person mvds; 05.08.2010
comment
Когда вы сказали вы, вы конкретно имели в виду меня или всех? Код опасен, если воспринимать его легкомысленно. - person Anraiki; 06.08.2010

была такая же проблема и обошла ее, используя функцию PHP ftp_delete

person WIGPIP    schedule 07.06.2011

Другое предложение: не хранить файлы на диске, а помещать их в базу данных. Это сохраняет очень четкое различие между вашим сайтом + скриптами и «пользовательскими данными».

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

person mvds    schedule 05.08.2010
comment
В случае с изображениями я не думаю, что это хорошая идея хранить их в базе данных (по соображениям производительности). Потому что при их отображении вам нужен PHP-скрипт для чтения из базы данных. Поскольку изображения представляют собой отдельные HTTP-запросы, это приведет к множественным подключениям к базе данных, которые необходимо установить. - person JochenJung; 05.08.2010
comment
К вашему сведению, Microsoft SharePoint 3.0 делает это (хранит файлы в БД). Я не обязательно согласен с этим решением, так как считаю, что «файловая система» должна использоваться для хранения «файлов», а «базы данных» — для табличных данных. Но этот шаблон проектирования имел бы смысл в некоторых сценариях. - person Wadih M.; 05.08.2010
comment
Пожалуйста, объясните мне, почему файловая система не является базой данных? На неэкзотических объемах производительность точно не проблема, судя по опыту. Соединение с базой данных может сохраняться между запросами. Вы должны взвесить недостатки (производительность) и достоинства (простота обслуживания, резервное копирование, согласованность данных, аспекты безопасности, как в исходном вопросе). Подумайте о настройке репликации mysql, ужас, связанный с репликацией файлов! - person mvds; 05.08.2010
comment
@mvds Я согласен, поддержка двоичных данных файла и метаданных файла через файловую систему может быть нетривиальной задачей, особенно когда происходит межплатформенное взаимодействие (linux, windows и т. д.). Обе технологии имеют свои преимущества/недостатки. - person Wadih M.; 05.08.2010
comment
@Wadih: к счастью, не у всех из нас есть пропорции, подобные Facebook или YouTube, поэтому единственное преимущество файловой системы (производительность) не требуется. Оставляет много каверзных моментов - см. мой комментарий к @anraiki о 0 байтах в строках, в php по сравнению с базовыми функциями libc. - person mvds; 05.08.2010