如何使用 Perl 提供图像并具有一定的安全性和最少的资源?
我在这里找到了一些相关的帖子,但是没有什么正确的.. 我需要“正确”地提供图像(嗯)并使用尽可能少的资源。 我正在开发一个子项目(如下),但是,仅仅因为我使用 CGI,资源就不太友好。但这只是我的假设。我是 Perl 新手,但是,我比 php 更喜欢它。
查询将由“somescript.pl?img=image.png”生成,
#!/usr/bin/perl -Tw
use strict;
use warnings;
use CGI;
#I should drop warnings after all is said and done. Also name my vars generically. Right?
#I dont know if this query method will work or is even the best method.
$query = new CGI;
my @img = $query->param;
if ( $_ eq "img" ) { my $file = $query->param($_); }
if ( $_ ne "img" ) { ## I will send to an error sub that serves up a error image
}
# Prob a one liner to take care of the above. Not within my ability though.
# Still figuring all this out here.. Very verbose sorry...
# I will strip everything but lowercase alpha and the "."
# with s =~ /[something like A-Z] I will look it up //g;
# Still.. prob all above will fit in a one liner by a PERL guru!
# Below is related to -Taint, I was told this is important to use the -T.
$ENV{PATH} = "bin:/usr/bin";
delete( $ENV{qw(IFS CDPATH BASH_ENV ENV)} );
# now I will grab the images extension.
my $ext = ( $file =~ m/[^.]+$/ )[0];
#I was informed to use the "three" but, I am unsure what that means.
# My attempt based on my reading many posts here.
my $length = ( stat($file) )[10];
my $image = do {
local $/ = undef;
print "Content-type: image/$ext\n";
print "Content-length: $length \n\n";
binmode STDOUT;
open( FH, "<", $file ) || die "Could not find $file: $!";
my $buffer = "";
while ( read( FH, $buffer, 10240 ) ) {
print $buffer;
}
close(FH);
};
如您所见,我在这里的尝试显然是初学者。
我在堆栈溢出中找到了很好的建议。我感谢过去和现在的所有人。
I found some posts related here but, nothing right on..
I need to serve up an image (humm) "correctly" and using as little resources as possible.
I was working on a sub (below) but, is not too resource friendly just by the fact I use CGI. That is just my assumption though. I am a Perl newbie but, I like it better than php.
The query would be generated by "somescript.pl?img=image.png"
#!/usr/bin/perl -Tw
use strict;
use warnings;
use CGI;
#I should drop warnings after all is said and done. Also name my vars generically. Right?
#I dont know if this query method will work or is even the best method.
$query = new CGI;
my @img = $query->param;
if ( $_ eq "img" ) { my $file = $query->param($_); }
if ( $_ ne "img" ) { ## I will send to an error sub that serves up a error image
}
# Prob a one liner to take care of the above. Not within my ability though.
# Still figuring all this out here.. Very verbose sorry...
# I will strip everything but lowercase alpha and the "."
# with s =~ /[something like A-Z] I will look it up //g;
# Still.. prob all above will fit in a one liner by a PERL guru!
# Below is related to -Taint, I was told this is important to use the -T.
$ENV{PATH} = "bin:/usr/bin";
delete( $ENV{qw(IFS CDPATH BASH_ENV ENV)} );
# now I will grab the images extension.
my $ext = ( $file =~ m/[^.]+$/ )[0];
#I was informed to use the "three" but, I am unsure what that means.
# My attempt based on my reading many posts here.
my $length = ( stat($file) )[10];
my $image = do {
local $/ = undef;
print "Content-type: image/$ext\n";
print "Content-length: $length \n\n";
binmode STDOUT;
open( FH, "<", $file ) || die "Could not find $file: $!";
my $buffer = "";
while ( read( FH, $buffer, 10240 ) ) {
print $buffer;
}
close(FH);
};
As you can see, my attempt here is obviously a beginners.
I have found great advice here in stack overflow. I thank everyone past and present.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
.jpeg
而不是.jpg
!File::MMagic
或File::MimeInfo
将提供更好的通用解决方案。(stat $file)[10]
不是内容长度,而是ctime
,这对您来说毫无价值。(stat $file)[7]
有效,但-s $file
也同样有效,并且对于任何 Perl 程序员来说,它的作用都是显而易见的,而无需查阅>stat
手册。 (2a:打开文件后,在文件句柄上使用-s
而不是文件名,以避免与文件替换竞争。)image.pl?image=../../../../../../../etc/passwd
。我建议特别提及图像目录,以便您不依赖getcwd
,并使用File::Spec
->no_upwards
和File::Spec->catfile
构建只能在图像目录内的路径名。404
状态。如果请求非法,则返回400
或403
状态等。path_info
允许,您的网址会更好image.pl/foo.png
而不是image.pl?img=foo.png
。.jpeg
and not.jpg
!File::MMagic
orFile::MimeInfo
would make better general-purpose solutions.(stat $file)[10]
isn't the content-length, it's thectime
, which is worthless to you.(stat $file)[7]
works, but-s $file
works just as well and it's obvious to any Perl programmer what it does without having to consult thestat
manual. (2a: use-s
on the filehandle once you open it instead of the filename to avoid racing against file replacement.)image.pl?image=../../../../../../../etc/passwd
. I'd suggest specifically mentioning the images directory so that you're not dependent on thegetcwd
, and usingFile::Spec
->no_upwards
andFile::Spec->catfile
to build a pathname that can only be inside the images directory.die
if it's avoidable. If the file isn't found, return a404
status. If the request is illegal, return a400
or403
status, etc.path_info
to allowimage.pl/foo.png
instead ofimage.pl?img=foo.png
.看看 Apachegallery
http://metacpan.org/pod/Apache 中的实现方式: :Gallery
它使用 Imlib2,非常高效,包括动态调整大小和旋转以及使用共享磁盘缓存等高级功能。
Have a look at the way it is done in Apachegallery
http://metacpan.org/pod/Apache::Gallery
It's using Imlib2 and it is quite efficient, including advanced features as resizing and rotate on the fly and using a shared disk cache.
我认为你在这里遗漏了一些东西:
$_
未初始化。我想你想说的是:或者为了更好的可读性和可维护性
对于另一件事,你可能想使用
而不是
获取文件的长度。
(stat $file)[10]
将为您提供文件的更改时间。I think you're missing something here:
$_
is uninitialized. I think you wanted to say:or for better readability and maintainability
For another thing, you probably want to use
and not
to get the length of a file.
(stat $file)[10]
will give you the file's change time.提供图像的最简单方法是使用可能已包含在您的网络服务器中的文件处理。
您还可以使用
.htaccess
文件添加身份验证(如果您使用的是 Apache)。The simplest way to serve an image is by using the file handling that is probably already included in your webserver.
You can also add authentication by using an
.htaccess
file (if you're using Apache).我只会改变一些事情。
首先,将第一个注释块后面的代码块替换为:
您获取文件扩展名的代码对我不起作用。这样做:
我不明白“my $image = do {...”的用法。只是看起来没有必要。
由于您已经在使用 CGI 模块,因此可以使用它来为您处理标头:
读取文件并将其写回的方式在功能上看起来很完美。
我还有一些补充意见和建议。建议。首先,您的代码非常不安全。很高兴您正在考虑污染模式,但您没有对从客户端传入的文件名执行任何操作。例如,如果他们传递“/etc/passwd”怎么办?另一个原因是,您不妨在发送 HTTP 标头之前打开图像文件(在进行更多安全检查之后)。这将允许您向客户端发送一个合理的错误(404?),而不是直接死掉。使用 CGI 的“标头”方法可以使这变得简单。如果您愿意,您仍然可以向 STDERR 写入一些内容。
我现在能想到的就是这些。我希望这足以让你继续前进。
I would only change a few things.
First, replace the block of code after the first comment block with this:
Your code to get the file extension doesn't work for me. This does:
I do not understand the use of "my $image = do {...". It just doesn't seem necessary.
Since you're using the CGI module already, use it to do your headers for you:
The way you're reading the file and writing it back out looks functionally perfect.
I have several additional comments & suggestions. First, your code is extremely insecure. It's nice that you're thinking about taint mode, but you're not doing anything about the filename passed in from your client. What if they passed "/etc/passwd", for example? Another is that you might as well open your image file (after doing more security checks) before sending the HTTP headers. This would allow you to send a reasonable error back to the client (404?), rather than just dying. Use CGI's "header" method to make that easy. You can still write something to STDERR if you like.
That's all I can think of just now. I hope this is enough to get you going.
我不确定你想做什么,但看起来如果没有 Perl 和 CGI,处理这个问题会容易得多。您使用哪个服务器?我更愿意用 Apache 中的重写规则来解决这个问题。
不过,我从来都不喜欢看门人脚本。也许如果您能说出为什么要尝试这样做,我们就可以提出一个好的解决方案(而不仅仅是一个更好的解决方案:)。
I'm not sure what you are trying to do, but it looks like it would be much easier to handle this without Perl and CGI. Which server are you using? I'd prefer to fix this up with a rewrite rule in Apache.
I've never been a fan of gatekeeper scripts, though. Maybe if you can say why you are trying to do this we can come up with a good solution (and not just a better one :).