Permalink
Browse files

Throw exception on sanitizisation instead of silently renaming

  • Loading branch information...
1 parent e64b889 commit e5a8d59fd59c19e324a939b5fc2ae1e27870bc5e @cdujeu cdujeu committed Sep 21, 2016
@@ -0,0 +1,39 @@
+<?php
+/*
+ * Copyright 2007-2016 Abstrium <contact (at) pydio.com>
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The latest code can be found at <https://pydio.com/>.
+ */
+namespace Pydio\Core\Exception;
+
+defined('AJXP_EXEC') or die('Access not allowed');
+
+/**
+ * Class ForbiddenCharacterException
+ * @package Pydio\Core\Exception
+ */
+class ForbiddenCharacterException extends PydioException
+{
+ /**
+ * ForbiddenCharacterException constructor.
+ * @param string $originalString
+ */
+ public function __construct($originalString)
+ {
+ parent::__construct("$originalString contains forbbiden characters", null, 5012);
+ }
+}
@@ -21,6 +21,7 @@
namespace Pydio\Core\Utils\Vars;
use Psr\Http\Message\UploadedFileInterface;
+use Pydio\Core\Exception\ForbiddenCharacterException;
use Pydio\Core\Services\LocaleService;
defined('AJXP_EXEC') or die('Access not allowed');
@@ -137,14 +138,25 @@ public static function detectXSS($string)
* @param string $s
* @param int $level Can be InputFilter::SANITIZE_ALPHANUM, InputFilter::SANITIZE_EMAILCHARS, InputFilter::SANITIZE_HTML, InputFilter::SANITIZE_HTML_STRICT
* @param string $expand
+ * @param bool $throwException
* @return mixed|string
+ * @throws ForbiddenCharacterException
*/
- public static function sanitize($s, $level = InputFilter::SANITIZE_HTML, $expand = 'script|style|noframes|select|option')
+ public static function sanitize($s, $level = InputFilter::SANITIZE_HTML, $throwException = false, $expand = 'script|style|noframes|select|option')
{
+ $original = $s;
if ($level == InputFilter::SANITIZE_ALPHANUM) {
- return preg_replace("/[^a-zA-Z0-9_\-\.]/", "", $s);
+ $s = preg_replace("/[^a-zA-Z0-9_\-\.]/", "", $s);
+ if($throwException && $original !== $s){
+ throw new ForbiddenCharacterException($original);
+ }
+ return $s;
} else if ($level == InputFilter::SANITIZE_EMAILCHARS) {
- return preg_replace("/[^a-zA-Z0-9_\-\.@!%\+=|~\?]/", "", $s);
+ $s = preg_replace("/[^a-zA-Z0-9_\-\.@!%\+=|~\?]/", "", $s);
+ if($throwException && $original !== $s){
+ throw new ForbiddenCharacterException($original);
+ }
+ return $s;
} else if ($level == InputFilter::SANITIZE_FILENAME || $level == InputFilter::SANITIZE_DIRNAME) {
// Convert Hexadecimals
$s = preg_replace_callback('!(&#|\\\)[xX]([0-9a-fA-F]+);?!', function($array){
@@ -157,12 +169,18 @@ public static function sanitize($s, $level = InputFilter::SANITIZE_HTML, $expand
// Strip whitespace characters
$s = ltrim($s);
$s = str_replace(chr(0), "", $s);
- if ($level == InputFilter::SANITIZE_FILENAME) $s = preg_replace("/[\"\/\|\?\\\]/", "", $s);
- else $s = preg_replace("/[\"\|\?\\\]/", "", $s);
+ if ($level == InputFilter::SANITIZE_FILENAME) {
+ $s = preg_replace("/[\"\/\|\?\\\]/", "", $s);
+ } else {
+ $s = preg_replace("/[\"\|\?\\\]/", "", $s);
+ }
if (self::detectXSS($s)) {
if (strpos($s, "/") === 0) $s = "/XSS Detected - Rename Me";
else $s = "XSS Detected - Rename Me";
}
+ if($throwException && $original !== $s){
+ throw new ForbiddenCharacterException($original);
+ }
return $s;
}
@@ -203,6 +221,9 @@ public static function sanitize($s, $level = InputFilter::SANITIZE_HTML, $expand
} else {
$s = str_replace(array("<", ">"), array("&lt;", "&gt;"), $s);
}
+ if($throwException && $original !== $s){
+ throw new ForbiddenCharacterException($original);
+ }
return ltrim($s);
}
@@ -212,10 +233,11 @@ public static function sanitize($s, $level = InputFilter::SANITIZE_HTML, $expand
* @param $data
* @param int $sanitizeLevel
* @return string
+ * @throws ForbiddenCharacterException
*/
- public static function decodeSecureMagic($data, $sanitizeLevel = InputFilter::SANITIZE_HTML)
+ public static function decodeSecureMagic($data, $sanitizeLevel = InputFilter::SANITIZE_DIRNAME)
{
- return InputFilter::sanitize(InputFilter::securePath($data), $sanitizeLevel);
+ return InputFilter::sanitize(InputFilter::securePath($data), $sanitizeLevel, true);
}
/**
@@ -440,9 +440,10 @@ public function uploadAction(ServerRequestInterface &$request, ResponseInterface
InputFilter::parseFileDataErrors($uploadedFile, true);
// FIND PROPER FILE NAME / FILTER IF NECESSARY
- $userfile_name= InputFilter::sanitize(InputFilter::fromPostedFileName($uploadedFile->getClientFileName()), InputFilter::SANITIZE_FILENAME);
if (isSet($httpVars["urlencoded_filename"])) {
- $userfile_name = InputFilter::sanitize(urldecode($httpVars["urlencoded_filename"]), InputFilter::SANITIZE_FILENAME);
+ $userfile_name = InputFilter::sanitize(urldecode($httpVars["urlencoded_filename"]), InputFilter::SANITIZE_FILENAME, true);
+ }else{
+ $userfile_name= InputFilter::sanitize(InputFilter::fromPostedFileName($uploadedFile->getClientFileName()), InputFilter::SANITIZE_FILENAME, true);
}
$userfile_name = substr($userfile_name, 0, ConfService::getContextConf($ctx, "NODENAME_MAX_LENGTH"));
$this->logDebug("User filename ".$userfile_name);
@@ -2058,7 +2059,7 @@ public function rename($originalNode, $dest = null, $filename_new = null)
$mess = LocaleService::getMessages();
if(!empty($filename_new)){
- $filename_new= InputFilter::sanitize(InputFilter::magicDequote($filename_new), InputFilter::SANITIZE_FILENAME);
+ $filename_new= InputFilter::sanitize(InputFilter::magicDequote($filename_new), InputFilter::SANITIZE_FILENAME, true);
$filename_new = substr($filename_new, 0, ConfService::getContextConf($originalNode->getContext(), "NODENAME_MAX_LENGTH"));
}
@@ -81,7 +81,7 @@ public function receiveAction(\Psr\Http\Message\ServerRequestInterface &$request
case "compression":
- $archiveName = InputFilter::sanitize(InputFilter::decodeSecureMagic($httpVars["archive_name"]), InputFilter::SANITIZE_FILENAME);
+ $archiveName = InputFilter::decodeSecureMagic($httpVars["archive_name"], InputFilter::SANITIZE_FILENAME);
$archiveFormat = $httpVars["type_archive"];
$tabTypeArchive = array(".tar", ".tar.gz", ".tar.bz2");
$acceptedExtension = false;
@@ -82,7 +82,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
case "postcompress_download":
- $archive = ApplicationState::getAjxpTmpDir() . DIRECTORY_SEPARATOR . $httpVars["ope_id"] . "_" . InputFilter::sanitize(InputFilter::decodeSecureMagic($httpVars["archive_name"]), InputFilter::SANITIZE_FILENAME);
+ $archive = ApplicationState::getAjxpTmpDir() . DIRECTORY_SEPARATOR . $httpVars["ope_id"] . "_" . InputFilter::decodeSecureMagic($httpVars["archive_name"], InputFilter::SANITIZE_FILENAME);
$archiveName = $httpVars["archive_name"];
if (is_file($archive)) {
@@ -101,7 +101,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
case "compress" :
case "precompress" :
- $archiveName = InputFilter::sanitize(InputFilter::decodeSecureMagic($httpVars["archive_name"]), InputFilter::SANITIZE_FILENAME);
+ $archiveName = InputFilter::decodeSecureMagic($httpVars["archive_name"], InputFilter::SANITIZE_FILENAME);
$taskId = $request->getAttribute("pydio-task-id");
if ($taskId === null) {
Oops, something went wrong.

0 comments on commit e5a8d59

Please sign in to comment.