长沙分类信息网-长沙新闻网

PHP安全问题入门:10个常见安全问题+实例讲解

2024-2-21 3:39:41发布次查看发布人:
相对于其他几种语言来说, php 在 web 建站方面有更大的优势,即使是新手,也能很容易搭建一个网站出来。但这种优势也容易带来一些负面影响,因为很多的 php 教程没有涉及到安全方面的知识。
此帖子分为几部分,每部分会涵盖不同的安全威胁和应对策略。但是,这并不是说你做到这几点以后,就一定能避免你的网站出现任何问题。如果你想提高你的网站安全性的话,你应该继续通过阅读书籍或者文章,来研究如何提高你的网站安全性
出于演示需要,代码可能不是很完美。日常开发过程中,很多代码都包含在了框架跟各种库里面。作为一个后台开发,你不仅要熟练基本的curd,更要知道如何保护你的数据。
1. sql 注入
我赌一包辣条,你肯定会看到这里。 sql 注入是对您网站最大的威胁之一,如果您的数据库受到别人的 sql 注入的攻击的话,别人可以转出你的数据库,也许还会产生更严重的后果。
网站要从数据库中获取动态数据,就必须执行 sql 语句,举例如下:
$username = $_get[username];
$query = select * from users where username = $username;
攻击者控制通过 get 和 post 发送的查询(或者例如 ua 的一些其他查询)。一般情况下,你希望查询户名为「 peter 」的用户产生的 sql 语句如下:
select * from users where username = peter
但是,攻击者发送了特定的用户名参数,例如: or 1=1
这就会导致 sql 语句变成这样:
select * from users where username = peter or 1 = 1
这样,他就能在不需要密码的情况下导出你的整个用户表的数据了。
那么,我们如何防止这类事故的发生呢?主流的解决方法有两种。转义用户输入的数据或者使用封装好的语句。转义的方法是封装好一个函数,用来对用户提交的数据进行过滤,去掉有害的标签。但是,我不太推荐使用这个方法,因为比较容易忘记在每个地方都做此处理。
下面,我来介绍如何使用 pdo 执行封装好的语句( mysqi 也一样):
$username = $_get[username];
$query = $pdo->prepare(select * from users where username = :username);
$query->execute([username => $username]);
$data = $query->fetch();
动态数据的每个部分都以:做前缀。然后将所有参数作为数组传递给执行函数,看起来就像 pdo 为你转义了有害数据一样。
几乎所有的数据库驱动程序都支持封装好的语句,没有理由不使用它们!养成使用他们的习惯,以后就不会忘记了。
你也可以参考 phpdelusions 中的一篇关于动态构建 sql 查询时处理安全问题的文章。链接: l5rocks.com/en...
另外种 cookie 时,如果无需 js 读取的话,请必须设置为 /owasp/cheats....
4. lfi
lfi (本地文件包含) 是一个用户未经验证从磁盘读取文件的漏洞。
我经常遇到编程不规范的路由代码示例,它们不验证过滤用户的输入。我们用以下文件为例,将它要渲染的模板文件用 get 请求加载。
$page = $_get[page];
if(!$page) {
$page = main.php;
}
include($page);
>
由于 include 可以加载任何文件,不仅仅是php,攻击者可以将系统上的任何文件作为包含目标传递。
index.phppage=../../etc/passwd
这将导致 /etc/passwd 文件被读取并展示在浏览器上。
要防御此类攻击,你必须仔细考虑允许用户输入的类型,并删除可能有害的字符,如输入字符中的“.” “/” “”。
如果你真的想使用像这样的路由系统(我不建议以任何方式),你可以自动附加 php 扩展,删除任何非 [a-za-z0-9-_] 的字符,并指定从专用的模板文件夹中加载,以免被包含任何非模板文件。
我在不同的开发文档中,多次看到造成此类漏洞的 php 代码。从一开始就要有清晰的设计思路,允许所需要包含的文件类型,并删除掉多余的内容。你还可以构造要读取文件的绝对路径,并验证文件是否存在来作为保护,而不是任何位置都给予读取。
5. 不充分的密码哈希
大部分的 web 应用需要保存用户的认证信息。如果密码哈希做的足够好,在你的网站被攻破时,即可保护用户的密码不被非法读取。
首先,最不应该做的事情,就是把用户密码明文储存起来。大部分的用户会在多个网站上使用同一个密码,这是不可改变的事实。当你的网站被攻破,意味着用户的其他网站的账号也被攻破了。
其次,你不应该使用简单的哈希算法,事实上所有没有专门为密码哈希优化的算法都不应使用。哈希算法如 md5 或者 sha 设计初衷就是执行起来非常快。这不是你需要的,密码哈希的终极目标就是让黑客花费无穷尽的时间和精力都无法破解出来密码。
另外一个比较重要的点是你应该为密码哈希加盐(salt),加盐处理避免了两个同样的密码会产生同样哈希的问题。
以下使用 md5 来做例子,所以请千万不要使用 md5 来哈希你的密码, md5 是不安全的。
假如我们的用户 user1 和 user315 都有相同的密码 ilovecats123,这个密码虽然看起来是强密码,有字母有数字,但是在数据库里,两个用户的密码哈希数据将会是相同的:5e2b4d823db9d044ecd5e084b6d33ea5 。
如果一个如果黑客拿下了你的网站,获取到了这些哈希数据,他将不需要去暴力破解用户 user315 的密码。我们要尽量让他花大精力来破解你的密码,所以我们对数据进行加盐处理:
//warning: !!这是一个很不安全的密码哈希例子,请不要使用!!
$password = cat123;
$salt = random_bytes(20);
$hash = md5($password . $salt);
最后在保存你的唯一密码哈希数据时,请不要忘记连 $salt 也已经保存,否则你将无法验证用户。
在当下,最好的密码哈希选项是 bcrypt,这是专门为哈希密码而设计的哈希算法,同时这套哈希算法里还允许你配置一些参数来加大破解的难度。
新版的 php 中也自带了安全的密码哈希函数 password_hash ,此函数已经包含了加盐处理。对应的密码验证函数为 password_verify 用来检测密码是否正确。password_verify 还可有效防止 时序攻击.
以下是使用的例子:
//user signup
$password = $_post[password];
$hashedpassword = password_hash($password, password_default);
//login
$password = $_post[password];
$hash = 1234; //load this value from your db
if(password_verify($password, $hash)) {
echo password is valid!;
} else {
echo invalid password.;
}
需要澄清的一点是:密码哈希并不是密码加密。哈希(hash)是将目标文本转换成具有相同长度的、不可逆的杂凑字符串(或叫做消息摘要),而加密(encrypt)是将目标文本转换成具有不同长度的、可逆的密文。显然他们之间最大的区别是可逆性,在储存密码时,我们要的就是哈希这种不可逆的属性。
6. 中间人攻击
mitm (中间人) 攻击不是针对服务器直接攻击,而是针对用户进行,攻击者作为中间人欺骗服务器他是用户,欺骗用户他是服务器,从而来拦截用户与网站的流量,并从中注入恶意内容或者读取私密信息,通常发生在公共 wifi 网络中,也有可能发生在其他流量通过的地方,例如isp运营商。
对此的唯一防御是使用 /blog/20...小贴士
我不是一个安全专家,恐无法做到事无巨细。尽管编写安全软件是一个非常痛苦的过程,但还是可以通过遵循一些基本规则,编写合理安全的应用程序。其实,很多框架在这方面也帮我们做了很多工作。
在问题发生之前,安全性问题并不像语法错误等可以在开发阶段追踪到。因此,在编写代码的过程中,应该时刻有规避安全风险的意识。如果你迫于业务需求的压力而不得不暂时忽略一些安全防范的工作,我想你有必要事先告知大家这样做的潜在风险。
如果你从这篇文章有所收益,也请把它分享给你的朋友们把,让我们共建安全网站。
该用户其它信息

推荐信息

长沙分类信息网-长沙新闻网
关于本站