File Coverage

blib/lib/Image/Magick/Safer.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Image::Magick::Safer;
2              
3             =head1 NAME
4              
5             Image::Magick::Safer - Wrap Image::Magick Read method to check magic bytes
6              
7             =for html
8             Build Status
9             Coverage Status
10              
11             =head1 VERSION
12              
13             0.04
14              
15             =head1 SYNOPSIS
16              
17             use Image::Magick::Safer;
18              
19             # functions just like Image::Magick but wraps the Read method
20             # to check the magic bytes of any images using File::LibMagic
21             my $magick = Image::Magick::Safer->new;
22              
23             # if any @files have a MIME type that looks questionable then
24             # $e will be populated
25             if ( my $e = $magick->Read( @files ) ) {
26             # bail out, unsafe to continue
27             ....
28             }
29              
30             =head1 DESCRIPTION
31              
32             Image::Magick::Safer is a drop in wrapper around Image::Magick, it adds a
33             magic byte check to the C method to check the file MIME type using
34             L. If a file looks questionable then it will prevent the file
35             being passed to the real Image::Magick::Read method and return an error.
36             If a file cannot be opened, because it does not exist or it is prefixed
37             with a pipe, an error will also be returned.
38              
39             You can replace any calls to C with C
40             and the functionality will be retained with the added Read protection. The
41             aliases for C will also be made safe.
42              
43             If you need to override the default MIME types then you can set the modules
44             C<$Image::Magick::Safer::Unsafe> hash to something else or add extra types:
45              
46             # add SVG check to the defaults
47             $Image::Magick::Safer::Unsafe->{'image/svg+xml'} = 1;
48              
49             The default MIME types considered unsafe are as follows:
50              
51             text/plain
52             application/x-compress
53             application/x-compressed
54             application/gzip
55             application/bzip2
56             application/x-bzip2
57             application/x-gzip
58             application/x-rar
59             application/x-z
60             application/z
61              
62             Note that i make B that this will fix and/or protect you from
63             exploits, it's just another safety check. You should update to the latest
64             version of ImageMagick to protect yourself against potential exploits.
65              
66             Also note that to install the L module you will need to have
67             both the library (libmagic.so) and the header file (magic.h). See the perldoc
68             for L for more information.
69              
70             =head1 WHY ISN'T THIS A PATCH IN Image::Magick?
71              
72             Image::Magick moves at a glacial pace, and involves a 14,000 line XS file. No
73             thanks. This will probably get patched in the next version, so for the time
74             being this module exists.
75              
76             =cut
77              
78 1     1   14676 use strict;
  1         1  
  1         21  
79 1     1   3 use warnings;
  1         1  
  1         17  
80              
81 1     1   360 use parent 'Image::Magick';
  1         200  
  1         3  
82 1     1   806 use File::LibMagic;
  0            
  0            
83              
84             our $VERSION = '0.04';
85              
86             # imagemagick can automatically uncompress archive files so there's another
87             # attack vector in having an exploit image zipped up, so just checking for
88             # text/plain isn't enough
89             $Image::Magick::Safer::Unsafe = {
90             map { $_ => 1 }
91             'text/plain',
92             'application/x-compress',
93             'application/x-compressed',
94             'application/gzip',
95             'application/bzip2',
96             'application/x-bzip2',
97             'application/x-gzip',
98             'application/x-rar',
99             'application/x-z',
100             'application/z',
101             };
102              
103             my $magic;
104              
105             sub Read {
106             my ( $self,@images ) = @_;
107              
108             $magic ||= File::LibMagic->new;
109              
110             foreach my $image ( @images ) {
111              
112             # info has:
113             # mime_with_encoding
114             # description
115             # encoding
116             # mime_type
117             if ( my $info = $magic->info_from_filename( $image ) ) {
118              
119             $info->{mime_type} = ''
120             if ! defined $info->{mime_type};
121              
122             if ( $info->{mime_type} =~ /No such file or directory/i ) {
123             return $info->{mime_type};
124             }
125              
126             # if the mime_type is within the $Image::Magick::Safer::Unsafe
127             # hash or we can't figure it out then we assume it's not a real
128             # image and therefore could have an exploit within the file
129             if (
130             ! $info->{mime_type}
131             || $Image::Magick::Safer::Unsafe->{ $info->{mime_type} }
132             ) {
133             return "$image is of type @{[ $info->{mime_type} ]}, potentially unsafe";
134             }
135             } else {
136             return "unable to establish mime_type for $image";
137             }
138             }
139              
140             # all images *seem* ok, delegate to the real Image::Magick
141             return $self->SUPER::Read( @images );
142             }
143              
144             # Image::Magick has a few aliases for the Read method
145             *Image::Magick::Safer::ReadImage = *Image::Magick::Safer::Read;
146             *Image::Magick::Safer::read = *Image::Magick::Safer::Read;
147             *Image::Magick::Safer::readimage = *Image::Magick::Safer::Read;
148              
149             =head1 SEE ALSO
150              
151             L - the library this module wraps
152              
153             L - ImageMagick
154              
155             L - ImageMagick exploits
156              
157             L -
158             GraphicsMagick and ImageMagick popen() shell vulnerability via filename
159              
160             =head1 AUTHOR
161              
162             Lee Johnson - C
163              
164             =head1 LICENSE
165              
166             This library is free software; you can redistribute it and/or modify it under
167             the same terms as Perl itself. If you would like to contribute documentation,
168             features, bug fixes, or anything else then please raise an issue / pull request:
169              
170             https://github.com/Humanstate/image-magick-safer
171              
172             =cut
173              
174             1;