]> source.dussan.org Git - nextcloud-server.git/commitdiff
White-list known secure mime types. Refs. #8184
authorThomas Tanghus <thomas@tanghus.net>
Mon, 14 Apr 2014 15:17:50 +0000 (17:17 +0200)
committerThomas Tanghus <thomas@tanghus.net>
Mon, 14 Apr 2014 15:17:50 +0000 (17:17 +0200)
lib/private/connector/sabre/file.php
lib/private/files/type/detection.php
lib/private/helper.php
lib/private/mimetypes.list.php
tests/lib/helper.php

index ef6caaf22a740b9748f6d6b0b7494154cb15768b..750d646a8f588e5dbfa813881b1f7fef0498ebdc 100644 (file)
@@ -205,10 +205,12 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
         */
        public function getContentType() {
                if (isset($this->fileinfo_cache['mimetype'])) {
-                       return $this->fileinfo_cache['mimetype'];
+                       $mimeType = $this->fileinfo_cache['mimetype'];
+               } else {
+                       $mimeType = \OC\Files\Filesystem::getMimeType($this->path);
                }
 
-               return \OC\Files\Filesystem::getMimeType($this->path);
+               return \OC_Helper::getSecureMimeType($mimeType);
 
        }
 
index 11e439032ce3df8feeff5eaa60889942e92cc9ba..8ee53917814d50124ec980743d3d249f58ff1e4c 100644 (file)
@@ -17,24 +17,40 @@ namespace OC\Files\Type;
  */
 class Detection {
        protected $mimetypes = array();
+       protected $secureMimeTypes = array();
 
        /**
-        * add an extension -> mimetype mapping
+        * Add an extension -> mimetype mapping
+        *
+        * $mimetype is the assumed correct mime type
+        * The optional $secureMimeType is an alternative to send to send
+        * to avoid potential XSS.
         *
         * @param string $extension
         * @param string $mimetype
+        * @param string|null $secureMimeType
         */
-       public function registerType($extension, $mimetype) {
-               $this->mimetypes[$extension] = $mimetype;
+       public function registerType($extension, $mimetype, $secureMimeType = null) {
+               $this->mimetypes[$extension] = array($mimetype, $secureMimeType);
+               $this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype;
        }
 
        /**
-        * add an array of extension -> mimetype mappings
+        * Add an array of extension -> mimetype mappings
+        *
+        * The mimetype value is in itself an array where the first index is
+        * the assumed correct mimetype and the second is either a secure alternative
+        * or null if the correct is considered secure.
         *
         * @param array $types
         */
        public function registerTypeArray($types) {
                $this->mimetypes = array_merge($this->mimetypes, $types);
+
+               // Update the alternative mimetypes to avoid having to look them up each time.
+               foreach ($this->mimetypes as $mimeType) {
+                       $this->secureMimeTypes[$mimeType[0]] = $mimeType[1] ?: $mimeType[0];
+               }
        }
 
        /**
@@ -48,7 +64,9 @@ class Detection {
                        //try to guess the type by the file extension
                        $extension = strtolower(strrchr(basename($path), "."));
                        $extension = substr($extension, 1); //remove leading .
-                       return (isset($this->mimetypes[$extension])) ? $this->mimetypes[$extension] : 'application/octet-stream';
+                       return (isset($this->mimetypes[$extension]) && isset($this->mimetypes[$extension][0]))
+                               ? $this->mimetypes[$extension][0]
+                               : 'application/octet-stream';
                } else {
                        return 'application/octet-stream';
                }
@@ -123,4 +141,16 @@ class Detection {
                        return $mime;
                }
        }
+
+       /**
+        * Get a secure mimetype that won't expose potential XSS.
+        *
+        * @param string $mimeType
+        * @return string
+        */
+       public function getSecureMimeType($mimeType) {
+               return isset($this->secureMimeTypes[$mimeType])
+                       ? $this->secureMimeTypes[$mimeType]
+                       : 'application/octet-stream';
+       }
 }
index da3d3cd1c6ea55f0042f9e14adafcee55a851281..d5214823de9a88f5847c855d63fc30da2e95c272 100644 (file)
@@ -430,6 +430,16 @@ class OC_Helper {
                return self::getMimetypeDetector()->detect($path);
        }
 
+       /**
+        * Get a secure mimetype that won't expose potential XSS.
+        *
+        * @param string $mimeType
+        * @return string
+        */
+       static function getSecureMimeType($mimeType) {
+               return self::getMimetypeDetector()->getSecureMimeType($mimeType);
+       }
+
        /**
         * get the mimetype form a data string
         *
index 91bcf584267604fb08da84c2661fb979f7d0b086..cdfd2ec0fdd189e95f58ea826846a331eaf953af 100644 (file)
  * Array mapping file extensions to mimetypes (in alphabetical order).
  */
 return array(
-       '7z' => 'application/x-7z-compressed',
-       'accdb' => 'application/msaccess',
-       'ai' => 'application/illustrator',
-       'avi' => 'video/x-msvideo',
-       'bash' => 'text/x-shellscript',
-       'blend' => 'application/x-blender',
-       'bin' => 'application/x-bin',
-       'bmp' => 'image/bmp',
-       'cb7' => 'application/x-cbr',
-       'cba' => 'application/x-cbr',
-       'cbr' => 'application/x-cbr',
-       'cbt' => 'application/x-cbr',
-       'cbtc' => 'application/x-cbr',
-       'cbz' => 'application/x-cbr',
-       'cc' => 'text/x-c',
-       'cdr' => 'application/coreldraw',
-       'cpp' => 'text/x-c++src',
-       'css' => 'text/css',
-       'csv' => 'text/csv',
-       'cvbdl' => 'application/x-cbr',
-       'c' => 'text/x-c',
-       'c++' => 'text/x-c++src',
-       'deb' => 'application/x-deb',
-       'doc' => 'application/msword',
-       'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-       'dot' => 'application/msword',
-       'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
-       'dv' => 'video/dv',
-       'eot' => 'application/vnd.ms-fontobject',
-       'epub' => 'application/epub+zip',
-       'exe' => 'application/x-ms-dos-executable',
-       'flac' => 'audio/flac',
-       'gif' => 'image/gif',
-       'gz' => 'application/x-gzip',
-       'gzip' => 'application/x-gzip',
-       'html' => 'text/html',
-       'htm' => 'text/html',
-       'ical' => 'text/calendar',
-       'ics' => 'text/calendar',
-       'impress' => 'text/impress',
-       'jpeg' => 'image/jpeg',
-       'jpg' => 'image/jpeg',
-       'js' => 'application/javascript',
-       'json' => 'application/json',
-       'keynote' => 'application/x-iwork-keynote-sffkey',
-       'kra' => 'application/x-krita',
-       'm2t' => 'video/mp2t',
-       'm4v' => 'video/mp4',
-       'markdown' => 'text/markdown',
-       'mdown' => 'text/markdown',
-       'md' => 'text/markdown',
-       'mdb' => 'application/msaccess',
-       'mdwn' => 'text/markdown',
-       'mkv' => 'video/x-matroska',
-       'mobi' => 'application/x-mobipocket-ebook',
-       'mov' => 'video/quicktime',
-       'mp3' => 'audio/mpeg',
-       'mp4' => 'video/mp4',
-       'mpeg' => 'video/mpeg',
-       'mpg' => 'video/mpeg',
-       'msi' => 'application/x-msi',
-       'numbers' => 'application/x-iwork-numbers-sffnumbers',
-       'odg' => 'application/vnd.oasis.opendocument.graphics',
-       'odp' => 'application/vnd.oasis.opendocument.presentation',
-       'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
-       'odt' => 'application/vnd.oasis.opendocument.text',
-       'oga' => 'audio/ogg',
-       'ogg' => 'audio/ogg',
-       'ogv' => 'video/ogg',
-       'otf' => 'font/opentype',
-       'pages' => 'application/x-iwork-pages-sffpages',
-       'pdf' => 'application/pdf',
-       'php' => 'application/x-php',
-       'pl' => 'application/x-perl',
-       'png' => 'image/png',
-       'ppt' => 'application/mspowerpoint',
-       'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
-       'psd' => 'application/x-photoshop',
-       'py' => 'text/x-python',
-       'rar' => 'application/x-rar-compressed',
-       'reveal' => 'text/reveal',
-       'sgf' => 'application/sgf',
-       'sh-lib' => 'text/x-shellscript',
-       'sh' => 'text/x-shellscript',
-       'svg' => 'image/svg+xml',
-       'swf' => 'application/x-shockwave-flash',
-       'tar' => 'application/x-tar',
-       'tar.gz' => 'application/x-compressed',
-       'tex' => 'application/x-tex',
-       'tgz' => 'application/x-compressed',
-       'tiff' => 'image/tiff',
-       'tif' => 'image/tiff',
-       'ttf' => 'application/x-font-ttf',
-       'txt' => 'text/plain',
-       'vcard' => 'text/vcard',
-       'vcf' => 'text/vcard',
-       'wav' => 'audio/wav',
-       'webm' => 'video/webm',
-       'woff' => 'application/font-woff',
-       'wmv' => 'video/x-ms-asf',
-       'xcf' => 'application/x-gimp',
-       'xls' => 'application/msexcel',
-       'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
-       'xml' => 'application/xml',
-       'zip' => 'application/zip',
+       '7z' => array('application/x-7z-compressed', null),
+       'accdb' => array('application/msaccess', null),
+       'ai' => array('application/illustrator', null),
+       'avi' => array('video/x-msvideo', null),
+       'bash' => array('text/x-shellscript', null),
+       'blend' => array('application/x-blender', null),
+       'bin' => array('application/x-bin', null),
+       'bmp' => array('image/bmp', null),
+       'cb7' => array('application/x-cbr', null),
+       'cba' => array('application/x-cbr', null),
+       'cbr' => array('application/x-cbr', null),
+       'cbt' => array('application/x-cbr', null),
+       'cbtc' => array('application/x-cbr', null),
+       'cbz' => array('application/x-cbr', null),
+       'cc' => array('text/x-c', null),
+       'cdr' => array('application/coreldraw', null),
+       'cpp' => array('text/x-c++src', null),
+       'css' => array('text/css', null),
+       'csv' => array('text/csv', null),
+       'cvbdl' => array('application/x-cbr', null),
+       'c' => array('text/x-c', null),
+       'c++' => array('text/x-c++src', null),
+       'deb' => array('application/x-deb', null),
+       'doc' => array('application/msword', null),
+       'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', null),
+       'dot' => array('application/msword', null),
+       'dotx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.template', null),
+       'dv' => array('video/dv', null),
+       'eot' => array('application/vnd.ms-fontobject', null),
+       'epub' => array('application/epub+zip', null),
+       'exe' => array('application/x-ms-dos-executable', null),
+       'flac' => array('audio/flac', null),
+       'gif' => array('image/gif', null),
+       'gz' => array('application/x-gzip', null),
+       'gzip' => array('application/x-gzip', null),
+       'html' => array('text/html', 'text/plain'),
+       'htm' => array('text/html', 'text/plain'),
+       'ical' => array('text/calendar', null),
+       'ics' => array('text/calendar', null),
+       'impress' => array('text/impress', null),
+       'jpeg' => array('image/jpeg', null),
+       'jpg' => array('image/jpeg', null),
+       'js' => array('application/javascript', 'text/plain'),
+       'json' => array('application/json', 'text/plain'),
+       'keynote' => array('application/x-iwork-keynote-sffkey', null),
+       'kra' => array('application/x-krita', null),
+       'm2t' => array('video/mp2t', null),
+       'm4v' => array('video/mp4', null),
+       'markdown' => array('text/markdown', null),
+       'mdown' => array('text/markdown', null),
+       'md' => array('text/markdown', null),
+       'mdb' => array('application/msaccess', null),
+       'mdwn' => array('text/markdown', null),
+       'mkv' => array('video/x-matroska', null),
+       'mobi' => array('application/x-mobipocket-ebook', null),
+       'mov' => array('video/quicktime', null),
+       'mp3' => array('audio/mpeg', null),
+       'mp4' => array('video/mp4', null),
+       'mpeg' => array('video/mpeg', null),
+       'mpg' => array('video/mpeg', null),
+       'msi' => array('application/x-msi', null),
+       'numbers' => array('application/x-iwork-numbers-sffnumbers', null),
+       'odg' => array('application/vnd.oasis.opendocument.graphics', null),
+       'odp' => array('application/vnd.oasis.opendocument.presentation', null),
+       'ods' => array('application/vnd.oasis.opendocument.spreadsheet', null),
+       'odt' => array('application/vnd.oasis.opendocument.text', null),
+       'oga' => array('audio/ogg', null),
+       'ogg' => array('audio/ogg', null),
+       'ogv' => array('video/ogg', null),
+       'otf' => array('font/opentype', null),
+       'pages' => array('application/x-iwork-pages-sffpages', null),
+       'pdf' => array('application/pdf', null),
+       'php' => array('application/x-php', null),
+       'pl' => array('application/x-perl', null),
+       'png' => array('image/png', null),
+       'ppt' => array('application/mspowerpoint', null),
+       'pptx' => array('application/vnd.openxmlformats-officedocument.presentationml.presentation', null),
+       'psd' => array('application/x-photoshop', null),
+       'py' => array('text/x-python', null),
+       'rar' => array('application/x-rar-compressed', null),
+       'reveal' => array('text/reveal', null),
+       'sgf' => array('application/sgf', null),
+       'sh-lib' => array('text/x-shellscript', null),
+       'sh' => array('text/x-shellscript', null),
+       'svg' => array('image/svg+xml', 'text/plain'),
+       'swf' => array('application/x-shockwave-flash', 'application/octet-stream'),
+       'tar' => array('application/x-tar', null),
+       'tar.gz' => array('application/x-compressed', null),
+       'tex' => array('application/x-tex', null),
+       'tgz' => array('application/x-compressed', null),
+       'tiff' => array('image/tiff', null),
+       'tif' => array('image/tiff', null),
+       'ttf' => array('application/x-font-ttf', null),
+       'txt' => array('text/plain', null),
+       'vcard' => array('text/vcard', null),
+       'vcf' => array('text/vcard', null),
+       'wav' => array('audio/wav', null),
+       'webm' => array('video/webm', null),
+       'woff' => array('application/font-woff', null),
+       'wmv' => array('video/x-ms-asf', null),
+       'xcf' => array('application/x-gimp', null),
+       'xls' => array('application/msexcel', null),
+       'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', null),
+       'xml' => array('application/xml', 'text/plain'),
+       'zip' => array('application/zip', null),
 );
index 0943e6bc1b9db79f8b16743a4eeaaa0190d74aaa..5d319e40f02b180c4cccf05b91fadb21ac6a3798 100644 (file)
@@ -71,6 +71,18 @@ class Test_Helper extends PHPUnit_Framework_TestCase {
                $this->assertEquals($result, $expected);
        }
 
+       function testGetSecureMimeType() {
+               $dir=OC::$SERVERROOT.'/tests/data';
+
+               $result = OC_Helper::getSecureMimeType('image/svg+xml');
+               $expected = 'text/plain';
+               $this->assertEquals($result, $expected);
+
+               $result = OC_Helper::getSecureMimeType('image/png');
+               $expected = 'image/png';
+               $this->assertEquals($result, $expected);
+       }
+
        function testGetFileNameMimeType() {
                $this->assertEquals('text/plain', OC_Helper::getFileNameMimeType('foo.txt'));
                $this->assertEquals('image/png', OC_Helper::getFileNameMimeType('foo.png'));