0

In one PHP page I collect some data on the server (i.e. a list of the file in a folder) and show it into a table. The user may require to delete one file. Because I'm new to PHP I don't know if my approach is correct. Let's see some code:

list.php

<?php
$path = "/path/to/directory/";
$files = array_diff(scandir($path), array('.', '..'));
?>

<?php for ($i = 0; $i < count($files); $i++) { ?>
    <tr>
        <td class="d-none"><?php echo "{$i}"?></td>
        <td><?php echo "{$files[$i]}"?></td>
        <td>
            <button type="button" class="btn btn-danger btn-sm delete"><i class="fas fa-trash-alt"></i></button>
        </td>                                                               
    </tr>
<?php } ?>  

index.js

$(document).on("click", ".delete", function(e) {
    var id = $(this).closest("tr").find('td').eq(0).html();
    var filename = $(this).closest("tr").find('td').eq(1).html();

    $.ajax({
        url: "delete.php?id=" + id,
        type: 'DELETE',
        success: function(result) {
            alert(result);
        }
    });
});

delete.php

$url = $_SERVER["REQUEST_URI"];
$query = parse_url($url, PHP_URL_QUERY);
parse_str($query, $params); 
$id = $params["id"]; 
$path = "/path/to/directory/";
//$filename = ???;
//unlink($path . $filename);
echo "success";

Some options I thought:

  1. Instead of the id pass the filename as parameter of the DELETE query. I guess it's not a good way.
  2. list.php should place the file names into a db, so I can access them everywhere. Actually I did it, on a "live" db in /dev/shm but I wonder if it's a valid approach. Every time the page reloads I need to drop the table and create it again (on the page there's a refresh button for this purpose)
  3. use the $_SESSION variable to store the array so the delete.php page can retrieve the filename by its id.

Please note, I'm not asking for an opinion about the three options. I'm asking what is the right approach from a technical point of view: safety, performances, reliability, etc...

5
  • Very broad to answer on also still this would be a primarily opinion-based question.. Commented Oct 6, 2019 at 16:50
  • .. also whats is the point of the system? is it required a trusted person (by trusted authentication) to possible delete files in a directory? Commented Oct 6, 2019 at 17:14
  • @RaymondNijland yes, it's a development machine and there's one specific directory where users can load and remove files (using the web app). For this reason the path is hard-coded: they can only choose the filename, not the path. Commented Oct 6, 2019 at 17:16
  • 1
    Well the safety is as strong as the weakest link, so if the authentication method/layer is leak the whole system after is also simply unsafe.. Also consider reasking this on codereview.stackexchange.com or security.stackexchange.com as this question is more or less in the gray area of been considerd offtopic here... Also be ready to post more of your code when asked for then poeple can give much more solid advice instead of guessing.. Commented Oct 6, 2019 at 17:26
  • 1
    Speaking of trusted authentication -> There is a new web standard which is called Web Authentication .. also better explained on Guide to Web Authentication ... it's a javascript API which can use windows hello/usb token for example to register/login on you in on a webapplication.. The link explains how it works on the browser side and in some detail in minimal what a webapplication should do to keep it safe. Browser support are the modern Edge, Firefox and Chrome browsers versions... But i think there already might be PHP libs Commented Oct 6, 2019 at 17:34

2 Answers 2

2

Option 1 is okay, If you just want a fast and easy internal solution. But making the filename visible can lead to security vulnerabilties. (See comments below)

Option 2 is much slower and DB and filesystem information might get out of sync If you access the FS from somewhere else, too. (Or you need to reload it all the time, as you stated).

But if you make sure that every Access to the FS is done via your PHP code this could be the best way. When adding new files you can make an entry in the DB. Every access to it also needs to go via your code and update the DB entry If needed. Reloading the DB every time would no longer be necessary and this could be a good Implementation.

Option 3 is similar to 1. However it can solve the problem with visible filenames and still be simple as you don't need a DB.

Sign up to request clarification or add additional context in comments.

11 Comments

Are you aware that how you suggesting crypting and decrypting to "hide" a filename is a from of security by obscurity -> "Security Through Obscurity (STO) is the belief that a system of any sort can be secure so long as nobody outside of its implementation group is allowed to find out anything about its internal mechanisms. ... Once the secret gets out, that is the end of your security."
It is, if you lets say simply use an md5 hash. But if you use a 'real' encryption it isn't. Add a salt and you are fine. Or am I missing your point?
"Or am I missing your point?" i indeed think you are missing mine point of mine first comment .. As MD5 hash is not encryption.. Also MD5 is not even to be considerd safe anymore nowadays..
No, that was a misleading example of mine. I was in hurry, sorry. So again: It is an STO if you only use an md5 hash for hiding the filename. If instead, you use a real encryption, with a secure hash function like sha and also add a salt etc. it is not.
Oh, and thinking about it i came up with another problem. When you are using a plain id in the query you make it possible to easily delete all available files, even If the user might not know them. You could Just use: delete.php?id=1 and delete.php?id=2 and so on.
|
0

Use a PHP Framework like Slim, and start to do things right. You're not even using HTML Method DELETE. With your code a POST call to delete.php will delete anything that you set in the URL. With Slim your code will be like that, and you will not go to hell:

    <?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->delete('/', function (Request $request, Response $response, array $args) {
    $id = $request->get('id');
    $path = "/path/to/directory/";
    //$filename = ???;
    //unlink($path . $filename);
    $response->getBody()->write("success");
    return $response;
});

$app->run();

By the way, remember to take a look to Composer.

2 Comments

Usually I don't want to use Frameworks or third-part code, without understand what I'm doing first. Anyway, I will give it a look. Thanks for the hint.
So what you want is to use PHP like all those people who have gotten PHP to be in the shit place. You can do things by yourself, but you're going to spend a lot of time, and probably you won't get a code as secure and reliable as a probed and widely used framework. Trust me, the composer way is the nice way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.