Christian pleasure. I start with telling you: "sorry for my english but in years of studies i don't speak very well". Anyway.... I've a website developed with design pattern MVC, in this website the user can upload php file and run his. For using this file uploaded, the user have an a token: example.com/home/profile/advance?token=XXXXXXXXXXXXXX I would that this file uploaded from user can't interact with my server as if it were inside a virtual machine. It possible? I hope I explained myself.
Asked
Active
Viewed 27 times
0
-
You may find this question useful: https://stackoverflow.com/questions/3695858/how-do-sites-like-codepad-org-and-ideone-com-sandbox-your-program – Havenard Nov 08 '18 at 22:32
-
a website, or a single file? if it's the latter, use a chroot jail? – hanshenrik Nov 08 '18 at 22:39
-
Blocking every possible way for this to be exploited is very difficult. This is why most sites that let you upload or modify code such as fiddle or w3schools don't actually offer that functionality for PHP because even if you can contain the code, making sure people don't use it to exploit your system resources for malicious or illegal activity would be nearly impossible. – Nosajimiki Nov 08 '18 at 22:46
-
thank you for your help. execute only one file. anyway, yes as codepad or ideone. it's true, chroot... but how to use it? I don't thinks you intend http://php.net/manual/en/function.chroot.php – Christian Nov 08 '18 at 23:09
1 Answers
0
That's absolute possible. Just append the user's token to your form uploader:
<?php
$token = 'xxx';
?>
<form action="home/profile/advance?token=<?php echo htmlentities(urlencode($token)); ?>" method="post" enctype="multipart/form-data">
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
This will make a $_POST
to home/profile/advance?token=xxx
.
Note that a server-side generated token should only contain alphanumeric characters, but it's best to wrap it in htmlentities()
and urlencode()
to be safe.
However, note that allowing users to upload (and run) their own PHP files is a huge security risk! I would strongly recommend not allowing them to run PHP, but instead limiting allowed uploads to raw .txt
files. There's several different vectors to consider here, so I would recommend implementing the following (courtesy of CertaiN, with minor modification):
<?php
header('Content-Type: text/plain; charset=utf-8');
try {
// Undefined | Multiple Files | $_FILES Corruption Attack
// If this request falls under any of them, treat it invalid.
if (
!isset($_FILES['upfile']['error']) ||
is_array($_FILES['upfile']['error'])
) {
throw new RuntimeException('Invalid parameters.');
}
// Check $_FILES['upfile']['error'] value.
switch ($_FILES['upfile']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException('No file sent.');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException('Exceeded filesize limit.');
default:
throw new RuntimeException('Unknown errors.');
}
// You should also check filesize here.
if ($_FILES['upfile']['size'] > 1000000) {
throw new RuntimeException('Exceeded filesize limit.');
}
// DO NOT TRUST $_FILES['upfile']['mime'] VALUE !!
// Check MIME Type by yourself.
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (false === $ext = array_search(
$finfo->file($_FILES['upfile']['tmp_name']),
array(
'txt' => 'text/plain',
),
true
)) {
throw new RuntimeException('Invalid file format.');
}
// You should name it uniquely.
// DO NOT USE $_FILES['upfile']['name'] WITHOUT ANY VALIDATION !!
// On this example, obtain safe unique name from its binary data.
if (!move_uploaded_file(
$_FILES['upfile']['tmp_name'],
sprintf('./uploads/%s.%s',
sha1_file($_FILES['upfile']['tmp_name']),
$ext
)
)) {
throw new RuntimeException('Failed to move uploaded file.');
}
echo 'File is uploaded successfully.';
} catch (RuntimeException $e) {
echo $e->getMessage();
}

Obsidian Age
- 41,205
- 10
- 48
- 71
-
warning, you neither urlencoded nor html encoded $token here. that should have been `echo htmlentities(urlencode($token));` – hanshenrik Nov 08 '18 at 22:30
-
Pretty sure the main part of his question was "how to run user code in my server in a way that it is safe". – Havenard Nov 08 '18 at 22:31
-
I didn't mean this. I would execute this file such as it inside a virtual machine in this way the user it can not do damage and interact with my physical website – Christian Nov 08 '18 at 22:34
-
@Christian Ideone.com is a very popular website that does exactly that, you may use this website name as keyword to find a solution to your problem, just like I found a related question. You can probably solve 90% of this problem by just forcing a call to `chroot()` in the beginning of the user script so that it can no longer see the rest of the server and will be isolated to it's own directory, but I wouldn't stop there. There are a bunch of functions that you should restrict access to, and make sure there's no way to undo the `chroot()` thing etc. – Havenard Nov 08 '18 at 22:39
-
thank you for your help. execute only one file. anyway, yes as codepad or ideone. it's true, chroot... but how to use it? I don't thinks you intend http://php.net/manual/en/function.chroot.php – Christian Nov 09 '18 at 06:48