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.06
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   16308 use strict;
  1         1  
  1         21  
82 1     1   3 use warnings;
  1         1  
  1         25  
83              
84 1     1   437 use parent 'Image::Magick';
  1         202  
  1         19  
85 1     1   924 use File::LibMagic;
  0            
  0            
86              
87             our $VERSION = '0.06';
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 SEE ALSO
156              
157             L - the library this module wraps
158              
159             L - ImageMagick
160              
161             L - ImageMagick exploits
162              
163             L -
164             GraphicsMagick and ImageMagick popen() shell vulnerability via filename
165              
166             =head1 AUTHOR
167              
168             Lee Johnson - C
169              
170             =head1 LICENSE
171              
172             This library is free software; you can redistribute it and/or modify it under
173             the same terms as Perl itself. If you would like to contribute documentation,
174             features, bug fixes, or anything else then please raise an issue / pull request:
175              
176             https://github.com/Humanstate/image-magick-safer
177              
178             =cut
179              
180             1;