博主信息
博文
18
粉丝
0
评论
0
访问量
1836
积分:0
P豆:38

如何让PHP的代码更安全

2022年01月13日 21:09:06阅读数:110博客 /

概述
攻击者通过构造恶意SQL命令发送到数据库,如果程序未对用户输入的 SQL命令执行判断过滤,那么生成的SQL语句可能会绕过安全性检查,插入其他用于修改后端数据库的语句,并可能执行系统命令,从而对系统造成危害

例如删除 id 为 1 的帖子,sql 如下:
$post_id = $_POST[‘post_id’];
$sql = “DELETE FROM posts WHERE user_id = 1 AND id = $post_id”;
\DB::statement($sql);
如果有人在提交 post_id 时输入 1 OR 1 ,你的语句会组合成这样:
$sql = “DELETE FROM posts WHERE user_id = 1 AND id = 1 OR 1”;
一般比较常出现在原生的 SQL 操作,框架一般会解决这方面的问题。通常采用参数控制或过滤特殊字符避免上述的问题。

越权漏洞

  1. 水平越权
    水平越权就是同等角色下的用户,不但能够访问和操作自己私有的数据,还能访问其他人私有的数据,其根本是基于数据的访问权限。

删除用户收款方式的场景如下:

graph LR

用户登录—>token

token—>获取收款方式列表

获取收款方式列表—token—>通过id删除

通过收款方式 {id} 执行 delete 请求的路由为:localhost/api/payments/{id}

假如用户A的收款方式有{1,2,3} 用户B的收款方式有{4,5}

如果没有做数据控制,A 登录后携带 A 的 token 执行删除的接口localhost/api/payments/4,则会删除 B 的,所以需要对destory方法做数据控制

  1. # 1 删除前鉴权处理
  2. public function destory($id){
  3. $payment = Payment::find($id);
  4. if ($payment->user_id != $this->currentUser->id) {
  5. return ...
  6. }
  7. $payment->delete();
  8. }
  9. # 2 参入id查询删除
  10. public function destory($id){
  11. Payment::whereUserId($this->currentUser->id)->whereId($id)->delete();
  12. }
  13. # 3 模型关联查询
  14. class User extends Model{
  15. public function payments()
  16. {
  17. return $this->hasMany('App\Payment');
  18. }
  19. }
  20. class PaymentController extends Controller{
  21. public function destory($id)
  22. {
  23. $this->currentUser->payments()->whereId($id)->delete();
  24. }
  25. }

推荐使用第三种方式做数据控制,不然面向对象白学了。获取收款方式的列表同样需要数据权限控制,用户和收款方式存在一对多的关联关系,模型关联后,获取用户收款方式列表可以写成
class PaymentController extends Controller{
public function index($id)
{

  1. #带条件的查询
  2. $payments = $this->currentUser->payments()->where(function($query){
  3. ...
  4. })->get();
  5. #不带条件的查询
  6. $payments = $this->currentUser->payments;
  7. }
  1. 垂直越权
    低权限的角色通过一些途径,获得高权限的能力,就发生了越权访问。如普通用户 guest 修改 admin 用户的密码;guest 可直接进入后台取得域名管理、用户管理等所有权限

解决这个问题,需要把权限职责以最小颗粒细分,基于 RBAC 设计权限管理系统。分为以下关联模型

graph LR

用户—多对多—>角色

用户—多对多—>权限

角色—多对多—>权限

每次执行请求时,在前置中间件判断这个用户是否永远该执行请求的权限,无权限则驳回。

  1. 上下文越权
    攻击者能够利用应用程序状态机中的漏洞获得关键资源的访问权限,这就存在上下文相关的越权。上下文相关的越权漏洞一般属于业务逻辑漏洞。 如在找回密码过程中,攻击者使用自己的账户信息通过验证,将他人的密码进行了修改。

graph LR

1.邮箱验证—>2.找回密码

在步骤1之后,执行找回密码,路由为 。如果此时没有校验当前找回密码的账户是否为进行邮箱校验后的账户,由可能产生越权漏洞.

路由 : 【PUT 】localhost/api/users/find-password,接收参数 email,new_password.

错误:校验和修改分成 2 步localhost/api/email/check->localhost/api/users/password
class UserController extends Controller{
public function check($data)
{
if (checkEmail($data[‘email’], $data[‘code’])) {
return true;
}

}

  1. public function findPassword()
  2. {
  3. $user = User::whereEmail($data['email'])->first();
  4. $user->password = bcrypt($data['new_password']);
  5. $user->save();
  6. }

}
正确:在 findPassword 里面再次验证完成邮箱校验的账户是否为当前找回密码的账号
class UserController extends Controller{

  1. public function check($data)
  2. {
  3. if (checkEmail($data['email'], $data['code'])) {
  4. return true;
  5. }
  6. ...
  7. }
  8. public function findPassword($data)
  9. {
  10. if (checkEmail($data['email'], $data['code'])) {
  11. $user = User::whereEmail($data['email'])->first();
  12. $user->password = $data['new_password'];
  13. $user->save();

限制分页条目范围,防止恶意请求
public function index($params){
$pageId = $params[‘pageid’] ?? PAGE_ID; //页码
$pageSize = $params[‘pagesize’] ?? 15; //条码

  1. $articles = Article::where(function ($query) use ($params) {
  2. ...
  3. })->take($pageSize)->skip($pageId * $pageSize)->orderby('id', 'desc')->get();
  4. ...
  5. ...

}
以上代码如果没有限制 pagesize 的范围,恶意请求者请求把 pagesize 输入 5000,10000 等甚至更大的数,会给数据库带来一定的压力,localhost/api/articles?pageid=0&pagesize=10000
//用框架自带的分页方法
public function index(){
$builder = Article::with(‘category:id,name’)->orderBy(‘id’, ‘desc’)->paginate(8);
return response()->json([‘status’ => true, ‘count’ => $builder->total(), ‘articles’ => $builder->items()]);
}
JWT 的 Token 需要二次加密
许多拓展包加密出的token并不十分安全,用base64_decode可以解密获取 加密主键、载荷等重要信息,所以通常需要对JWT的token进行二次加密

限制上传文件的类型

对于一个图片上传的接口,如果没有对上传文件的格式做限制,攻击者很有可能把 .php后缀的文件上传到public/images目录下,然后通过根目录执行这个文件。

需要设计安全的文件上传功能避免上述问题

1.文件上传的目录设置为不可执行

2.判断文件类型

3.使用随机数改写文件名和文件路径

4.单独设置文件服务器的域名

禁止或者避免写自动解压.zip 等压缩文件的代码

单纯地限制文件或压缩包大小并没有用,一个ZIP炸弹的.zip文件仅有 42 KB,但在解压后会占用 4718592 GB

避免登录密码被暴力破解

1.设定严格的速率限制,如登录次数限制,登录错误次数达 x 次时暂停登录 n 分钟

2.密码加上随机盐
public function reg(){
$user = new User;
$salt = radom(6);
$user->password = bcrypt($data[‘password’] . $salt);
做好异常处理,避免在生产环境中不正确的错误报告暴露敏感数据

如果你不小心,可能会在生产环境中因为不正确的错误报告泄露了敏感信息,例如:文件夹结构、数据库结构、连接信息与用户信息。

1.在.env 文件中关闭调试模式

APP_DEBUG=true

2.php 错误控制 error_reporting、display_errors
<?php
// 关闭错误报告
error_reporting(0);

// 报告 runtime 错误
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// 报告所有错误
error_reporting(E_ALL);

// 等同 error_reporting(E_ALL);
ini_set(“error_reporting”, E_ALL);

// 报告 E_NOTICE 之外的所有错误
error_reporting(E_ALL & ~E_NOTICE);
?>
display_errors = Off
php 弱语言的设计缺陷如:in_array
$array=[0,1,2,’3’];

var_dump(in_array(‘abc’, $array)); //true

var_dump(in_array(‘1bc’, $array)); //true

上面的情况返回的都是 true, 因为’abc’会转换为 0,’1bc’转换为 1

$a = null;
$b = false;
echo $a==$b; //true

$c = “”;
$d = 0;
echo $c==$d //true
在一些重要的地方需要使用===来作数据判断。

LFI (本地文件包含)
LFI (本地文件包含) 是一个用户未经验证从磁盘读取文件的漏洞。

不验证过滤用户的输入 将它要渲染的模板文件用 GET 请求加载。

<body>
<?php
$page = $_GET[‘page’];
if(!$page) {
$page = ‘main.php’;
}
include($page);
?></body>
由于 Include 可以加载任何文件,不仅仅是 PHP,攻击者可以将系统上的任何文件作为包含目标传递。

index.php?page=../../etc/passwd

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

要防御此类攻击,你必须仔细考虑允许用户输入的类型,并删除可能有害的字符,如输入字符中的 “.” “/” “\”。

XSS
XSS 又叫 CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往 Web 页面里插入恶意 html 代码,当用户浏览该页之时,嵌入其中 Web 里面的 html 代码会被执行,从而达到恶意攻击用户的特殊目的。

<body>
<?php
$searchQuery = $_GET[‘q’];
/ some search magic here /
?><h1>You searched for: <?php echo $searchQuery; ?></h1></body>
因为我们把用户的内容直接打印出来,不经过任何过滤,非法用户可以拼接 URL: search.php?q=%3Cscript%3Ealert(1)%3B%3C%2Fscript%3E

PHP 渲染出来的内容如下,可以看到 Javascript 代码会被直接执行:

<body>

<h1>You searched for: <script>alert(1);</script></h1>

<p>We found: Absolutely nothing because this is a demo</p>
</body>
Javascript 可以:

偷走你用户浏览器里的 Cookie;
通过浏览器的记住密码功能获取到你的站点登录账号和密码;
盗取用户的机密信息;
你的用户在站点上能做到的事情,有了 JS 权限执行权限就都能做,也就是说 A 用户可以模拟成为任何用户;
在你的网页中嵌入恶意代码;
使用htmlentities()过滤特殊字符,防止大部分的 xss 攻击

CSRF (跨站请求伪造)
例如网站上有用户可以用来注销账户的链接。

<a href="http://your-website.com/delete-account" rel="external nofollow" >销毁账户</a>
如果某个用户评论:

<img src=”http://your-website.com/delete-account”> wow
用户将在查看此评论的时候删除他们的账号。

laravel 的 web 路由默认开启了 csrf 验证,原理是在客户端产生一个随机的 token,在表单校验时判断这个 token 是否是这个页面上的请求

以上就是如何让PHP的代码更安全的详细内容

版权申明:本博文版权归博主所有,转载请注明地址!如有侵权、违法,请联系admin@php.cn举报处理!

全部评论

文明上网理性发言,请遵守新闻评论服务协议

条评论
  • javascript栏目介绍消除if else, 看起来优雅,一起来看看吧。
    ThinkPHP隐藏后台?下面本篇文章就来给大家介绍一下ThinkPHP巧用路由规则隐藏后台方法,网站
    果想快速进行php web开发,选择一个好用php开发框架至关重要,一个好php开发框架可以开发工作变得加快捷、和有效。那2022年最流行php开发框架有哪些呢?
    编写JS短?下面本篇文章就来给大家分享4个编写短小精炼JS小技巧,希望对大家有所帮助!
    在本文中,我们将讨论JS 中Set对象快— 特别扩展性方便。 Array 和Set工作方式存在大量交叉。但是使用Set会比Array在运行速度有优势。
    在本文中,我们将讨论JS 中Set对象快— 特别扩展性方便。 Array 和Set工作方式存在大量交叉。但是使用Set会比Array在运行速度有优势。
    写出优雅耐看PHP?本篇文章带大家了解一下PHP基本书写规范和框架规范,了解它们PHP优雅一个档次!
    你知道基于PHP新闻发布系统该书写出来吗?想必好多大学生期末考试都会你们用PHP开发一些系统之类,还不赶快学起来!!!
    开源程序都存在系统漏洞和不特点,因为使用用户越来越多,加上源开放等,容易被发现漏洞,所有修改后台管理目录,就显得有必要了。废话少说,下面就说一下修改ECSHOP后台目录。

    2021-03-01

    366

    php是开源。由于PHP解释器是公开,所以系数较高网站可以自己PHP解释程序;另外,PHP 运行环境使用也是免费
    php不能处理太大图片解决办法:1、对PHP内存分配大小进行调整,“ini_set("memory_limit", "512M");”;2、修改限制
    PHP 7里程版本PHP 7.4于2019年11月28日正式发布。因此,现在该我们深入研究一些最令人兴奋新增功能和新功能,这些功能将使PHP快,可靠。 。
    这篇文章主要介绍了PHP使用POP3读取邮箱接收邮件,文中示例非常详细,帮助大家理解和学习,感兴趣朋友可以了解下。
    上篇文章给大家介绍了《PHP中什么是URL.session id?他们之间有什么隐患?session id作用?​》,本文继续给大家介绍PHP中什么是递归函数?基本要素是什么?他用途是什么?
    下面由composer教程栏目给大家介绍composer装过程详解,希望对需要朋友有所帮助!
    之前写过一篇文章说明使用vim-plug去装vim插件,可能有些同学就会有疑问了,那么我要怎么去寻找自己想要插件呢?
    php字符串翻转是“strrev(string)”,参数string用于规定要翻转字符串;果传递给它是数字而不是字符串,它也会翻转该数字。