手机版

10个常见PHP安全问题示例分析

时间:2021-08-21 来源:互联网 编辑:宝哥软件园 浏览:

与其他语言相比,PHP在构建网站方面更有优势。即使是初学者也可以轻松建立网站。但是这种优势很容易带来一些负面影响,因为很多PHP教程都没有涉及安全知识。

本文分为几个部分,每个部分将涵盖不同的安全威胁和对策。然而,这并不是说你做了这些事情之后,就能够避免你的网站出现任何问题。如果你想提高网站的安全性,你应该通过阅读书籍或文章来继续研究如何提高网站的安全性

对于演示目的来说,代码可能并不完美。在日常的开发过程中,很多代码都包含在框架和各种库中。作为一个后台开发人员,你不仅要精通基本的凝乳,还要知道如何保护你的数据。

1.SQL注入

我赌一包辣条,你肯定会在这里看到。SQL注入是你网站最大的威胁之一。如果你的数据库被别人的SQL注入攻击,别人可以把你的数据库转移出去,可能会有更严重的后果。

要从数据库中获取动态数据,网站必须执行SQL语句,例如:

?PHP $ username=$ _ GET[' username '];$ query=' SELECT * FROM user WHERE username=' $ username ';攻击者控制通过GET和POST(或其他一些查询,如UA)发送的查询。通常,您希望查询由帐户名为“peter”的用户生成的SQL语句,如下所示:

从用户中选择*用户名='彼得'

但是,攻击者发送了特定的用户名参数,例如:“OR”1=“1”

这将导致SQL语句如下所示:

从用户名=' Peter '或' 1'=' 1 '的用户中选择*以便他可以在没有密码的情况下导出整个用户表的数据。

那么,如何才能防止此类事故的发生呢?有两种主流解决方案。转义用户输入的数据或使用封装的语句。escape方法是封装一个函数,对用户提交的数据进行过滤,去掉有害标签。但是,我不推荐这种方法,因为到处都很容易忘记做。

接下来,我将介绍如何使用PDO来执行封装的语句(以及mysqi):

$ username=$ _ GET[' username '];$ query=$ PDO-prepare(' SELECT * FROM users WHERE username=: username ');$ query-execute([' username '=$ username]);$ data=$ query-fetch();动态数据的每个部分都带有前缀:然后将所有参数作为数组传递给正在执行的函数,这看起来像是PDO为您转义了有害数据。

几乎所有的数据库驱动程序都支持封装语句,所以没有理由不使用它们!养成使用它们的习惯,以后就不会忘记了。

2.跨站脚本

XSS也叫CSS(跨站点脚本),是一种跨站点脚本攻击。它指的是恶意攻击者将恶意html代码插入网页。当用户浏览页面时,网页中嵌入的html代码就会被执行,从而达到恶意攻击用户的特殊目的。

以搜索页面为例:

尸体?PHP $ search query=$ _ GET[' q '];/*这里有些搜索魔法*/?h1你搜索了:php echo $ searchQuery?/h1pwefound :绝对没什么因为这是一个demo/p/body因为我们直接打印用户的内容没有任何过滤,非法用户可以拼接网址:

search.php?q= PHP渲染的内容如下,可以看到会直接执行Javascript代码:

bodyh1You您搜索了: script alert(1);/script/h1pwefound :绝对没什么因为这是一个demo/p/body q:执行JS代码有什么大不了的?

Javascript可以是:

偷饼干;从用户的浏览器;

通过浏览器的记住密码功能获取你的站点登录账号和密码;

窃取用户机密信息;

你的用户在网站上能做什么,都可以在JS权限下完成,也就是说A用户可以模拟成任何用户;

在网页中嵌入恶意代码;

.

问:如何预防这个问题?

好消息是,高级浏览器现在有一些基本的XSS预防功能,但请不要依赖它们。

正确的方法是永远不要相信用户的任何输入,并过滤掉输入中的所有特殊字符。这将消除大多数XSS攻击:

?PHP $ search query=htmlentities($ search query,ENT _ QUOTES);或者您可以使用模板引擎Twig,通用模板引擎将默认为output plus htmlentities。

如果你保持用户的输入,特别注意输出。在以下示例中,我们允许用户填写他们的博客链接:

正文?php echo $ homepageUrl?'Rel=' external nofollow '访问用户主页/a/body上述代码乍一看可能没有问题,但假设用户填写了以下内容:

#“onclick=”警报(1)将呈现为:

body a href=' # ' rel=' external no follow ' onclick=' alert(1)'访问用户主页/a/body永远不要相信用户输入的数据,或者总是假设用户的内容具有攻击性,他的态度是正确的,然后小心翼翼地处理每一个用户的输入和输出。

另外,在设置Cookie的时候,如果不需要JS读取,就必须设置为‘HTTP ONLY’。这个设置可以防止JavaScript从PHP读取Cookie。

3.XSRF/CSRF

CSRF是跨站请求伪造的缩写,意思是攻击者通过某种技术手段,欺骗用户访问曾经认证过的网站,并运行一些操作。

虽然这里显示的例子是一个GET请求,但它比POST更容易理解,而且它不是一种保护手段。也不是私有Cookies或多步骤形式。

假设您有一个允许用户删除帐户的页面,如下所示:

?PHP//delete-account . PHP $ confirm=$ _ GET[' confirm '];如果($ confirm===' yes '){//再见}攻击者可以在其网站上构建一个触发此URL的表单(这也适用于POST表单),或者将该URL加载为图片以吸引用户点击:

img src=' http :https://example.com/delete-account . PHP?确认=是/一旦触发,用户就会执行删除账号的指令,你的账号一眨眼就消失了。

防御这种攻击比防御XSS和SQL注入更复杂。

最常见的防御方法是生成CSRF令牌加密安全字符串,通常称为令牌,并将令牌存储在Cookie或Session中。

每次在网页上构建表单时,将令牌放在表单的隐藏字段中。表单请求服务器将根据用户或会话的Cookie比较令牌,并成功通过验证。

攻击者不能冒充用户,因为他不知道Token的内容(每个表单的Token都是随机的)。

?Php /*您在表单中嵌入的页面*/?表单操作='/delete-account.php '方法='post '输入类型='hidden '名称='csrf '值='?PHP echo $ _ SESSION[' csrf '];'输入类型='隐藏'名称='确认'值='是'/输入类型='提交'值='删除我的帐户'/表单##?PHP//delete-account . PHP $ confirm=$ _ POST[' confirm '];$ csrf=$ _ POST[' csrf '];$ knownGoodToken=$ _ SESSION[' csrf '];if($csrf!==$ knowngodtoken){ die('无效请求');} if($ confirm===' yes '){//再见}请注意,这是一个非常简单的示例,您可以添加更多代码。如果你使用的是像Symfony这样的PHP框架,你就有了CSRF令牌的功能。

4.览会

LFI(本地文件包含)是一个漏洞,用户在没有验证的情况下从磁盘读取文件。

我经常遇到不规则编程的路由代码示例,它们不验证和过滤用户输入。让我们以下面的文件为例,用GET请求加载要呈现的模板文件。

尸体?PHP $ page=$ _ GET[' page '];if(!$ page){ $ page=' main . PHP ';} include($ page);/body因为Include可以加载任何文件,而不仅仅是PHP,所以攻击者可以将系统上的任何文件作为including目标。

index.php?页面=././etc/passwd

这将导致/etc/passwd文件被读取并显示在浏览器上。

为了抵御此类攻击,您必须仔细考虑允许用户输入的类型,并删除潜在的有害字符,如" ""/""\".

如果你真的想用这样的路由系统(我不推荐任何方式),可以自动附加PHP扩展,删除除[a-zA-Z0-9-_]以外的任何字符,指定从特殊的模板文件夹加载,避免任何非模板文件。

我在不同的开发文档中见过许多导致这种漏洞的PHP代码。从一开始就要有明确的设计思路,允许包含文件的类型,删除多余的内容。您也可以构造要读取的文件的绝对路径,并验证该文件是否存在以进行保护,而不是到处读取。

5.密码哈希不充分

大多数Web应用程序都需要保存用户身份验证信息。如果密码散列做得足够好,当你的网站被攻破时,你可以保护用户的密码不被非法读取。

首先,最后要做的是以纯文本形式存储用户密码。大多数用户会在多个网站上使用同一个密码,这是不可改变的事实。当你的网站被攻破,就意味着用户其他网站的账号也被攻破了。

其次,你不应该使用简单的散列算法。事实上,所有未针对密码哈希优化的算法都不应使用。哈希算法,如MD5或SHA,旨在非常快速地执行。这不是你需要的。密码哈希的最终目的是让黑客花费无尽的时间和精力来破解密码。

另一个要点是,您应该对密码哈希进行Salt,这样可以避免两个相同的密码会产生相同的哈希的问题。

下面以MD5为例,请不要用MD5来哈希你的密码。MD5不安全。

我们的用户user1和user315都有相同的密码ilovecats123。虽然这个密码看起来像是带有字母和数字的强密码,但是在数据库中,这两个用户的密码哈希数据将是相同的:5e2b4d 823 db 9d 04 ecd5e 084 b 6d 33 ea 5。

如果黑客摧毁了你的网站并获得了这些散列数据,他就不需要暴力破解user315的密码。我们希望他花尽可能多的精力破解您的密码,因此我们对数据进行了盐处理:

?PHP//warn :这是一个非常不安全的密码哈希示例,请不要使用它!$ password=' cat123$ salt=random _ bytes(20);$hash=md5($password。$盐);最后,在保存您的唯一密码哈希数据时,请不要忘记,即使是$salt也已保存,否则您将无法验证用户。

目前,最好的密码散列选项是bcrypt,这是一种专门为散列密码而设计的散列算法。同时,这种哈希算法还允许你配置一些参数来增加破解难度。

新版本的PHP还附带了一个安全的密码哈希函数password_hash,它已经包含了salt处理。对应的密码验证功能是password_verify,用于检测密码是否正确。Password_verify还可以有效防止定时攻击。

以下是使用示例:

?PHP//用户注册$ password=$ _ POST[' password '];$ hashedPassword=PASSWORD _ hash($ PASSWORD,PASSWORD _ DEFAULT);//log in $ password=$ _ POST[' password '];$ hash=' 1234//从dbif(password_verify($password,$hash))中加载此值{ echo 'Password有效!';} else { echo '无效密码';}需要澄清的一点是,密码哈希不是密码加密。Hash是将目标文本转换为长度相同的不可逆哈希字符串(或消息摘要),Encrypt是将目标文本转换为长度不同的可逆密文。显然,它们之间最大的区别是可逆性。存储密码时,我们想要的是哈希的不可逆属性。

6.中间进攻的人

MITM(中间人)攻击不是针对服务器,而是针对用户。作为中间人,攻击者欺骗服务器说自己是用户,欺骗用户说自己是服务器,从而拦截用户与网站之间的流量,注入恶意内容或从中读取隐私信息,这种情况通常发生在公共WiFi网络中,也可能发生在流量经过的其他地方,比如ISP运营商。

对此的唯一防御措施是使用HTTPS,它可以加密您的连接,并且不能读取或篡改流量。你可以从我们加密获得免费的SSL证书,或者从其他供应商那里购买。这里不详细介绍如何正确配置WEB服务器,因为它与应用安全无关,很大程度上取决于您的设置。

你也可以采取一些措施使HTTPS更加安全。向网络服务器配置添加严格传输安全标头。这个标题信息告诉浏览器,你的网站总是通过HTTPS访问。如果它未能通过HTTPS,将返回一个错误报告,提示浏览器不显示此页面。

然而,这里有一个明显的问题。如果浏览器以前从未访问过你的网站,它不会知道你使用了这个标题,所以你需要使用Hstspreload。

你可以在这里注册你的网站: https://hstspreload.org/

您在此提交的所有网站都将被标记为仅HTTPS,并被硬编码到谷歌Chrome、FireFox、Opera、Safari、IE11和Edge的源代码中。

还可以在DNS配置中添加证书颁发机构授权(CAA)记录,只有一个证书颁发机构(比如Let’s encrypt)可以颁发你的域名证书,进一步提高了用户的安全性。

7.命令注入

这可能是服务器遇到的最严重的攻击。命令注入的目的是欺骗服务器执行任意的Shell命令

如果使用shell_exec或exec函数。让我们做一个小例子,允许用户简单地从服务器Ping不同的主机。

?PHP $ TargetIP=$ _ GET[' IP '];$ output=shell _ exec(' ping-c 5 $ TargetIP ');输出将包括到目标主机的5次pings。除非使用sh命令执行Shell脚本,否则攻击者可以执行他想要的任何操作。

ping.php?IP=8 . 8 . 8 . 8;ls -l /etcShell会执行Ping和攻击者拼接的第二个命令,这显然是非常危险的。

感谢PHP提供了一个函数来转义Shell参数。

Escapeshellarg转义用户的输入,并将其封装在单引号中。

?PHP $ TargetIP=escalateshellarg($ _ GET[' IP ']);$ output=shell _ exec(' ping-c 5 $ TargetIP ');现在你的命令应该很安全。我个人还是避免使用PHP调用外部命令,但这完全取决于你自己的喜好。

此外,我建议进一步验证用户输入是否符合您预期的形式。

8.设计缺陷

XXE (XML External Entity)是一种由本地文件包含引起的攻击,当应用程序使用配置不正确的XML解析器来解析外部XML时,甚至可以由远程代码执行。

XML有一个鲜为人知的特性,它允许文档作者将远程和本地文件作为实体包含在他们的XML文件中。

?xml版本='1.0 '编码='ISO-8859-1 '?DOCTYPE foo [!元素foo ANY!ENTITY passwd SYStem ' file :///etc/passwd ']foo passwd;/foo就像这样,/etc/passwd文件的内容被转储到XML文件中。

如果使用libxml,可以调用libxml_disable_entity_loader来保护自己免受这种攻击。请在使用之前仔细检查XML库的默认配置,以确保配置成功。

9.错误报告暴露了生产环境中的敏感数据

如果不小心,由于生产环境中不正确的错误报告,您可能会泄露敏感信息,如文件夹结构、数据库结构、连接信息和用户信息。

你不想让用户看到这个?

通常,根据您使用的框架或内容管理系统,配置方法会有所不同。通常,框架具有允许您将站点更改为生产环境的设置。这会将所有用户可见的错误消息重定向到日志文件,并向用户显示非描述性的500错误,同时允许您根据错误代码进行检查。

但是您应该根据您的PHP环境进行设置:error_reporting和display_errors。

10.登录限制

像登录这样的敏感形式应该有严格的速率限制,以防止暴力攻击。保存每个用户在过去几分钟内失败的登录尝试次数,如果该比率超过您定义的阈值,则拒绝进一步的登录尝试,直到冷却期结束。用户还可以通过电子邮件获得登录失败的通知,这样他们就知道自己的帐户已被锁定。

版权声明:10个常见PHP安全问题示例分析是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。