]> BookStack Code Mirror - bookstack/commitdiff
Hardened image file validation by removing custom validation
authorDan Brown <redacted>
Wed, 20 Mar 2019 23:59:55 +0000 (23:59 +0000)
committerDan Brown <redacted>
Wed, 20 Mar 2019 23:59:55 +0000 (23:59 +0000)
- Added test to check PHP files cannot be uploaded as an image.

app/Http/Controllers/ImageController.php
app/Providers/AppServiceProvider.php
resources/lang/en/validation.php
tests/Uploads/ImageTest.php
tests/Uploads/UsesImages.php
tests/test-data/bad.php [new file with mode: 0644]

index 4bd1b479c9316f8ac732cec7ff0a565b5082ba5a..a6c92bccc720f6869de3b579211482da714c2f94 100644 (file)
@@ -119,7 +119,7 @@ class ImageController extends Controller
     {
         $this->checkPermission('image-create-all');
         $this->validate($request, [
-            'file' => 'is_image'
+            'file' => 'mimes:jpeg,png,gif,bmp,webp,tiff'
         ]);
 
         if (!$this->imageRepo->isValidType($type)) {
@@ -135,7 +135,6 @@ class ImageController extends Controller
             return response($e->getMessage(), 500);
         }
 
-
         return response()->json($image);
     }
 
index 6fa0f9a5215b7c27dd0baadbda4e044c3b24fb29..77154baac6b2b4bdf3683c08815d998d306fe0e8 100644 (file)
@@ -21,12 +21,6 @@ class AppServiceProvider extends ServiceProvider
      */
     public function boot()
     {
-        // Custom validation methods
-        Validator::extend('is_image', function ($attribute, $value, $parameters, $validator) {
-            $imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/jpg', 'image/tiff', 'image/webp'];
-            return in_array($value->getMimeType(), $imageMimes);
-        });
-
         // Custom blade view directives
         Blade::directive('icon', function ($expression) {
             return "<?php echo icon($expression); ?>";
index e05cfca9dbe13222fdbc1f5ee492fb57fa5036d6..0b6a1c170a5fb31d7d470eedf61bb7a89bd96dbb 100644 (file)
@@ -69,7 +69,6 @@ return [
     'timezone'             => 'The :attribute must be a valid zone.',
     'unique'               => 'The :attribute has already been taken.',
     'url'                  => 'The :attribute format is invalid.',
-    'is_image'             => 'The :attribute must be a valid image.',
 
     // Custom validation lines
     'custom' => [
index 6dafa7f5a870bf553058cb9f42f9489c7d766b63..e264568244fe7cfba72822845929c320f8b232d9 100644 (file)
@@ -39,6 +39,28 @@ class ImageTest extends TestCase
         ]);
     }
 
+    public function test_php_files_cannot_be_uploaded()
+    {
+        $page = Page::first();
+        $admin = $this->getAdmin();
+        $this->actingAs($admin);
+
+        $fileName = 'bad.php';
+        $relPath = $this->getTestImagePath('gallery', $fileName);
+        $this->deleteImage($relPath);
+
+        $file = $this->getTestImage($fileName);
+        $upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery/upload', ['uploaded_to' => $page->id], [], ['file' => $file], []);
+        $upload->assertStatus(302);
+
+        $this->assertFalse(file_exists(public_path($relPath)), 'Uploaded php file was uploaded but should have been stopped');
+
+        $this->assertDatabaseMissing('images', [
+            'type' => 'gallery',
+            'name' => $fileName
+        ]);
+    }
+
     public function test_secure_images_uploads_to_correct_place()
     {
         config()->set('filesystems.default', 'local_secure');
index 16cb7c2b9a27742055ccd1044eaf352080165ddf..93bf278e21a91e9f7db0f676afe05a541686439d 100644 (file)
@@ -1,6 +1,8 @@
 <?php namespace Tests\Uploads;
 
 
+use Illuminate\Http\UploadedFile;
+
 trait UsesImages
 {
     /**
@@ -15,11 +17,11 @@ trait UsesImages
     /**
      * Get a test image that can be uploaded
      * @param $fileName
-     * @return \Illuminate\Http\UploadedFile
+     * @return UploadedFile
      */
     protected function getTestImage($fileName)
     {
-        return new \Illuminate\Http\UploadedFile($this->getTestImageFilePath(), $fileName, 'image/png', 5238);
+        return new UploadedFile($this->getTestImageFilePath(), $fileName, 'image/png', 5238, null, true);
     }
 
     /**
@@ -46,12 +48,14 @@ trait UsesImages
      * Uploads an image with the given name.
      * @param $name
      * @param int $uploadedTo
+     * @param string $contentType
      * @return \Illuminate\Foundation\Testing\TestResponse
      */
-    protected function uploadImage($name, $uploadedTo = 0)
+    protected function uploadImage($name, $uploadedTo = 0, $contentType = 'image/png')
     {
         $file = $this->getTestImage($name);
-        return $this->call('POST', '/images/gallery/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
+        return $this->withHeader('Content-Type', $contentType)
+            ->call('POST', '/images/gallery/upload', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []);
     }
 
     /**
diff --git a/tests/test-data/bad.php b/tests/test-data/bad.php
new file mode 100644 (file)
index 0000000..3b7c0f3
Binary files /dev/null and b/tests/test-data/bad.php differ