我正在一个网站上工作-目前尚处于测试的早期阶段,尚未启动,只有测试数据-谢天谢地。网站的“管理”页面*。我认为他们使用了朋友计算机上的按键记录器,该记录器登录了该站点以向我提供反馈。我进行了严格的检查,以便仅接受.jpg和.png文件-其他所有内容都应被拒绝。当然没有方法可以上传.jpg文件,然后在存储文件后更改扩展名吗?认为他们能够找到执行代码的文件。

我似乎无法弄清楚网站是如何允许PHP文件通过的。我的安全有什么问题?验证功能代码如下:一旦文件到达服务器,我将使用以下代码保留扩展名并生成一个新的随机名称。有点杂乱,但效果很好。它正确地将名称更改为logo.php;.jpg。对于123456.jpg,Windows不允许这样的文件名。


*网站上受保护的页面,其功能简单:例如上传图片,然后成为网站的新徽标。 FTP详细信息与用于登录网站上受保护页面的密码完全不同。以及数据库和cPanel凭据。我确保人们甚至都无法查看网站的文件夹和文件结构。如果您没有FTP的详细信息,实际上我无法想到将.jpg或.png扩展名重命名为.php。

评论

评论不作进一步讨论;此对话已移至聊天。

简短答案:通过设置代理可以轻松绕过客户端验证。他们可以先提交a.jpg并通过所有检查。然后,该请求将在代理处被拦截并更改为a.php。您需要在服务器端进行验证。

#1 楼

客户端验证
您提供的验证代码在JavaScript中。这表明您是用来在客户端上进行验证的代码。
保护Web应用程序安全的第一法则是永远不要信任客户端。客户端在用户(或本例中的攻击者)的完全控制下。您无法确定发送给客户端的任何代码都可用于任何用途,并且您放置在客户端上的任何块都没有任何安全性值。在客户端上进行验证仅是为了提供顺畅的用户体验,而不是实际上实施任何与安全性相关的约束。
攻击者可能只是在其浏览器中更改了JavaScript片段,或者完全关闭了脚本,或者只是不发送文件,但可以使用curl等工具编写自己的POST请求。
您需要重新验证服务器上的所有内容。这意味着您的PHP必须检查文件的类型是否正确,而您当前的代码则不然。
如何做到这一点是一个广泛的问题,我认为这不在您的问题范围内,但是这个问题是开始阅读的好地方。您可能还想看看.htaccess文件。神奇的PHP函数

当我从编辑框中存储数据时,我使用PHP的所有三个函数来清理它:您在验证文件扩展名的上下文中提到此事实的事实使我担心,您只是在输入中抛出了几个与安全性相关的函数,希望它可以解决问题。例如,您应该使用准备好的语句并且不能逃避SQLi的攻击。从数据库中检索数据后,需要对HTML标记和特殊字符进行转义以防止XSS,并且如何进行转储取决于插入数据的位置。等等,等等。
结论
我并不是说这个意思很刻薄,但是您似乎在这里犯了很多错误。如果还有其他漏洞,我也不会感到惊讶。如果您的应用程序处理了任何敏感信息,我强烈建议您让具有安全经验的人在将其投入生产之前先进行查看。

评论


举一个简单的例子:在Chrome中打开您的网站。按f12打开开发人员工具。选择来源标签。您会看到所有JavaScript,都已排列好并且可以很好地编辑。查找您的验证功能。删除它,并用return true替换;

–超级照明
17年1月4日在11:12

/ \不仅在Chrome中

– Marc.2377
17年1月4日在11:36

需要强调的一件事是“重新验证所有内容”-仅仅因为您正在服务器上进行验证并不意味着您不应该在浏览器中。只是不要将其用于安全性。这样,您的用户在发送表单之前,可以知道诸如“哦,我在电话号码中输入A,糟糕”之类的信息。

–曼上尉
17年5月5日在15:57

为了使事情变得更加有趣,总有多种语言...blog.portswigger.net/2016/12/…

– lorenzog
17年1月6日在11:16

@Cryptopat一些Node.js的东西

– noisypixy
17年1月8日在16:28

#2 楼

首先,如果有人利用文件上传功能,请确保您正在客户端和服务器上都验证文件。绕过客户端JavaScript保护是微不足道的。

其次,请确保您遍历并实施了OWASP的这些想法。还请确保您的服务器上没有其他未修补的缺陷(例如,过时的插件,可利用的服务器等)。

评论


您能否详细说明“ OWASP”的思想,将人们带离这里不一定是一件好事。即使将某些内容或想法引入此处,也会大大改善此答案。

–Möoz
17年1月5日在21:32

我同意@Mooz的观点,OWASP也是一个Wiki,也就是说,其中许多想法可以在以后进行编辑,其中一些想法可以在特定情况下帮助OP。如果您专注于添加可能对OP有所帮助的想法/实现,那么我可能会赞成...当前您的答案只是以前的答案/评论建议的副本(即使是在上传目录上禁用PHP的简单建议也比指向另一个网站上的一长串想法的链接)。

– CPHPython
17年1月9日在14:12

@CPHPython-我的糟糕。我会解决的。感谢您的注意。

– thel3l
17年1月10日在15:27

不必在客户端验证输入,这只是想为用户提供早期错误消息的便利,但是从安全角度来看,客户端验证毫无用处。

–user1067003
19年4月22日在15:51

#3 楼

这里要特别注意的是,PHP被设计为嵌入其他内容中。具体来说,它被设计为嵌入HTML页面中,并以少量动态更新的数据来补充大部分静态页面。解释程序将扫描任何文件类型,并执行所有已用脚本标签正确标记的PHP内容。如果Web服务器愿意通过PHP解释器过滤那些文件,那么该代码将执行。请参阅Wordpress“ Tim Thumb”插件惨败。

正确的解决方案是确保您的Web服务器永远不要将不受信任的内容视为应通过PHP运行的内容。尝试过滤输入是解决输入问题的一种方法,但是正如您所发现的那样,有限且容易出错。

更好地验证文件位置和文件扩展名都用于定义PHP将处理,并将上传内容和其他不受信任的内容隔离到不会被处理的位置和扩展名中。 (这样做的方式因服务器而异,并且遭受“使事情正常工作通常意味着以您不知道的方式放宽安全性”问题。)

评论


奇怪的是,timthumb PHP图像缩放器库已使用了这种性质(并不是说这是好事还是坏事)。本质上,字符串<?php die('Execution denied!'); //放在任何接触库的图像之前,从而有效地从另一个可能嵌入的脚本中窃取了节目。 -github.com/penibelst/timthumb/blob/master/timthumb.php

–路加·莱伯(Luke A. Leber)
17年1月6日在4:54



@ LukeA.Leber我想这是针对较旧的Tim Thumb问题的编码修复程序,该问题是嵌入在图像中的脚本左右向Wordpress服务器提供了所有权...我不确定是否要考虑一种优雅的解决方案还是一个笨拙的黑客: )

– gowenfawr
17年1月6日在5:04



我不会判断作者,但是当Joomla 3.4.8零时区问世时,我的内部启发式扫描器在3台服务器上的10,000张图像中打开了一个php标签,这让我感到非常恐惧。您可能会感到脸上流血的那一刻。

–路加·莱伯(Luke A. Leber)
17年1月6日在5:10

但是,您可以上传由解释器执行的脚本这一事实与PHP本身允许嵌入无关。与PHP一样,您可以上传Python或Ruby脚本。但是,问题是PHP和Apache(默认情况下)公开公开了服务器的目录结构,并允许您通过HTTP访问服务器上所需的任何文件。

–牛
18-09-27在7:13

#4 楼

您可以通过.htaccess禁用上载目录中的PHP,这样服务器就不会在该目录及其子目录中执行任何PHP代码。

使用以下规则在您的上载目录中创建一个.htaccess文件:

php_flag engine off


请注意,仅当您的PHP服务器以mod_php模式运行时,.htaccess规则才有效。

编辑:我忘了提及.htaccess仅适用于apache。

评论


请注意,.htaccess仅适用于apache。

– com2ghz
17年1月6日13:33

如果有人可以覆盖.htaccess文件,这将无济于事。

– wizzwizz4
20 Dec 31'的16:32

#5 楼

您仅在检查扩展名,这不一定与实际文件类型相关。在服务器端,您可以使用exif_imagetype之类的文件来验证文件是否为映像。
exif图像类型的用法:http://php.net/manual/en/function.exif-imagetype.php

评论


这可能是个好主意,但请记住(a)可以创建一个既可以用作图像又可以用作PHP的文件,并且(b)扩展名为.png的PHP文件对您的危害不大服务器,因为它将不会执行。

–安德斯
17年1月4日在14:41

@Anders,但它仍然是恶意代码,破坏它所需要的仅仅是某人/某事告诉它将foo.png作为PHP文件运行。尽管这不太可能,但我宁愿不要在口袋里装上口袋炸弹,即使我是唯一拥有雷管的炸弹也是如此。

–纤巧
17年1月4日在16:00

@Anders当然,除非将服务器配置为根据文件的内容而不是扩展名来解释文件。安全很难...

–罗安
17年1月4日在16:01

@Delioth Agreed,我有点儿怀疑了。我应该说的是,它没有那么危险,不是没有风险。

–安德斯
17年1月4日在16:22

#6 楼

我完全同意接受的答案,但我建议您做一些事情,而不仅仅是使用文件名。您应该使用GD或Imagick用PHP重新压缩原始/上传的文件,然后使用新映像。这样,您就可以销毁所有已注入的代码(老实说,90%的时间里,有一些方法可以使代码在压缩中幸存下来,但这是很多工作)。

您还可以使用.htaccess文件来阻止上传目录运行PHP代码(我不了解IIS,并且可能存在等效的.webconfig)。

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>


这样,仅当“最终扩展名”为PHP时,才会执行上传的文件,因此不会执行image.php.jpg。

一些资源:


关于文件上传的一篇不错的文章
PHP手动安装Apache


评论


“这样,仅当“最终扩展名”为PHP时,才会执行上载的文件,因此不会执行image.php.jpg。 —大概是针对OP所描述的网站类型,您只需在uploads目录中禁用PHP批发,而不必担心它具有什么文件扩展名。如果有人出于某种原因设法上传了以.php结尾的文件,则您仍然不希望其执行

–otherdave
17年1月10日在19:09

@anotherdave真的!主要部分是重新压缩图像...第二部分只是可以根据需要进行配置的其他部分

–akman
17年1月10日在19:14

#7 楼

这里解决方案的一个可能部分是保留图像,但也可以使用PHP调整大小后的副本,以便可以确保获取图像并减小原始图像的大小。这有几个积极的效果:


从不让原始图像用于显示,因此更安全
节省服务器空间(可能会或可能不会成问题)
网站访问者的加载时间更长,因为他们不必等待大约10 MB的图像加载。相反,它们以合理的大小加载了300 KB的图像

要点是,您永远无法信任用户数据。验证所有内容,文件上传,输入,cookie,以确保数据不会引起问题。

#8 楼

我要添加的一件事是尚未涉及的:使用白名单策略。

正如其他人已经指出的那样,仅依靠客户端验证当然不是一件好事。您还采用了黑名单策略,这意味着您要检查自己知道/认为不好的事情,并允许其他所有事情。更加健壮的策略是检查您认为可以的事情,并拒绝其他一切。图片。

根据我的经验,这两种策略不一定可以互斥,只要它们用于不同目的即可:用于用户反馈的客户端黑名单验证和服务器端白名单安全性验证。

#9 楼

我允许上传图片,但假设每个人都加载了木马代码。我在上传时将上传的图像临时放在Web根上方,然后使用ImageMagick将其转换为BMP,然后转换为JPG,然后将其移动到Web应用程序可以使用的位置。这有效地删除了任何嵌入式PHP代码。

正如@Sneftel在下面的注释中指出的那样,对JPG执行此转换将导致图像质量下降。就我的目的而言,这是可以接受的折衷方案。

评论


转换为BMP,然后转换为JPG,尤其是在输入为JPG的情况下,将导致明显的质量损失。重新打包图像不是一个坏主意,但是您应该以不会降低图像质量的方式进行处理。

–Sneftel
17年1月10日在10:42

就我们的目的而言,轻微的图像质量下降不是问题。

–编码员
17年1月10日在14:49

我正在使用RHEL 7附带的软件包,当前为ImageMagick 6.7

–编码员
17年1月11日在18:01

#10 楼

验证图像EXIF标记或使用strpos函数在图像内容中查找PHP代码。
示例:

$imageFile = file_get_contents($your_image_temp_path); // ATTENTION! Temporary path for images is really needed for security reasons!
$dangerousSyntax = ['<?', '<?php', '?>'];
$error = '';
foreach($dangerousSyntax as $value) {
  $find = strpos($value, $imageFile);
  if( $find !== true ) {
    unlink($your_image_temp_path);
    $error = 'We found a dangerous code in your image';
  }
}

if(!empty($error)) { 
  die($error);
}


评论


是什么让您认为任何给定的图像文件都不会包含字符“ <?”数据中的某处?

–Sneftel
17年1月10日在10:26

#11 楼

除了可接受的答案外,我建议使用PHP内置的getImageSize函数获取MIME类型,并确保PHP文件没有隐藏在图像文件扩展名下。

评论


您能否在答案中更详细地说明如何通过查询MIME类型来确保没有PHP标记?您是否在执行类似于示例1的操作,并使用任何可用类型重置Content-type标头?

– CPHPython
17年1月9日在14:35

@CPHPython除了已接受的答案外,该注释还将被起诉,以确保仅通过更改扩展名(例如,一个PHP文件,但名为image.jpeg)就不会上传任何PHP(或其他不正确的)文件类型。它不能为文件名中的代码提供任何安全性。

–灰色
17年4月13日在16:51