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.07
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             Leading pipes are also considered unsafe, as well as any reference to files
63             that cannot be found.
64              
65             Note that i make B that this will fix and/or protect you from
66             exploits, it's just another safety check. You should update to the latest
67             version of ImageMagick to protect yourself against potential exploits.
68              
69             Also note that to install the L module you will need to have
70             both the library (libmagic.so) and the header file (magic.h). See the perldoc
71             for L for more information.
72              
73             =head1 WHY ISN'T THIS A PATCH IN Image::Magick?
74              
75             Image::Magick moves at a glacial pace, and involves a 14,000 line XS file. No
76             thanks. This will probably get patched in the next version, so for the time
77             being this module exists.
78              
79             =cut
80              
81 1     1   14587 use strict;
  1         1  
  1         21  
82 1     1   3 use warnings;
  1         1  
  1         19  
83              
84 1     1   352 use parent 'Image::Magick';
  1         207  
  1         6  
85 1     1   1072 use File::LibMagic;
  0            
  0            
86              
87             our $VERSION = '0.07';
88              
89             # imagemagick can automatically uncompress archive files so there's another
90             # attack vector in having an exploit image zipped up, so just checking for
91             # text/plain isn't enough
92             $Image::Magick::Safer::Unsafe = {
93             map { $_ => 1 }
94             'text/plain',
95             'application/x-compress',
96             'application/x-compressed',
97             'application/gzip',
98             'application/bzip2',
99             'application/x-bzip2',
100             'application/x-gzip',
101             'application/x-rar',
102             'application/x-z',
103             'application/z',
104             };
105              
106             my $magic;
107              
108             sub Read {
109             my ( $self,@images ) = @_;
110              
111             $magic ||= File::LibMagic->new;
112              
113             foreach my $image ( @images ) {
114              
115             return "cannot open $image (file not found)" if ! -f $image;
116             return "cannot open $image (leading pipe)" if $image =~ /^\s*\|/;
117              
118             # info has:
119             # mime_with_encoding
120             # description
121             # encoding
122             # mime_type
123             if ( my $info = $magic->info_from_filename( $image ) ) {
124              
125             $info->{mime_type} = ''
126             if ! defined $info->{mime_type};
127              
128             if ( $info->{mime_type} =~ /No such file or directory/i ) {
129             return $info->{mime_type};
130             }
131              
132             # if the mime_type is within the $Image::Magick::Safer::Unsafe
133             # hash or we can't figure it out then we assume it's not a real
134             # image and therefore could have an exploit within the file
135             if (
136             ! $info->{mime_type}
137             || $Image::Magick::Safer::Unsafe->{ $info->{mime_type} }
138             ) {
139             return "$image is of type @{[ $info->{mime_type} ]}, potentially unsafe";
140             }
141             } else {
142             return "unable to establish mime_type for $image";
143             }
144             }
145              
146             # all images *seem* ok, delegate to the real Image::Magick
147             return $self->SUPER::Read( @images );
148             }
149              
150             # Image::Magick has a few aliases for the Read method
151             *Image::Magick::Safer::ReadImage = *Image::Magick::Safer::Read;
152             *Image::Magick::Safer::read = *Image::Magick::Safer::Read;
153             *Image::Magick::Safer::readimage = *Image::Magick::Safer::Read;
154              
155             =head1 KNOWN BUGS
156              
157             DOES NOT WORK with BSD 10.1 and 7.0.1 and i can't figure out why. If you can
158             figure out why then please submit a pull request. This is possibly some libmagic
159             weirdness going on.
160              
161             =head1 SEE ALSO
162              
163             L - the library this module wraps
164              
165             L - ImageMagick
166              
167             L - ImageMagick exploits
168              
169             L -
170             GraphicsMagick and ImageMagick popen() shell vulnerability via filename
171              
172             =head1 AUTHOR
173              
174             Lee Johnson - C
175              
176             =head1 LICENSE
177              
178             This library is free software; you can redistribute it and/or modify it under
179             the same terms as Perl itself. If you would like to contribute documentation,
180             features, bug fixes, or anything else then please raise an issue / pull request:
181              
182             https://github.com/Humanstate/image-magick-safer
183              
184             =cut
185              
186             1;