PHP代码安全有必要了解下
攻击者通过构造恶意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 删除前鉴权处理
public function destory($id){
$payment = Payment::find($id);
if ($payment->user_id != $this->currentUser->id) {
return ...
}
$payment->delete();
} # 2 参入id查询删除
public function destory($id){
Payment::whereUserId($this->currentUser->id)->whereId($id)->delete();
} # 3 模型关联查询
class User extends Model{
public function payments()
{
return $this->hasMany('App\Payment');
}
} class PaymentController extends Controller{
public function destory($id)
{
$this->currentUser->payments()->whereId($id)->delete();
}
}
推荐使用第三种方式做数据控制,不然面向对象白学了。获取收款方式的列表同样需要数据权限控制,用户和收款方式存在一对多的关联关系,模型关联后,获取用户收款方式列表可以写成
class PaymentController extends Controller{
public function index($id)
{
#带条件的查询
$payments = $this->currentUser->payments()->where(function($query){
...
})->get(); #不带条件的查询
$payments = $this->currentUser->payments;
}
}
2. 垂直越权
低权限的角色通过一些途径,获得高权限的能力,就发生了越权访问。如普通用户 guest 修改 admin 用户的密码;guest 可直接进入后台取得域名管理、用户管理等所有权限
解决这个问题,需要把权限职责以最小颗粒细分,基于 RBAC 设计权限管理系统。分为以下关联模型
graph LR
用户--多对多-->角色
用户--多对多-->权限
角色--多对多-->权限
每次执行请求时,在前置中间件判断这个用户是否永远该执行请求的权限,无权限则驳回。
3. 上下文越权
攻击者能够利用应用程序状态机中的漏洞获得关键资源的访问权限,这就存在上下文相关的越权。上下文相关的越权漏洞一般属于业务逻辑漏洞。 如在找回密码过程中,攻击者使用自己的账户信息通过验证,将他人的密码进行了修改。
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;
}
...
} public function findPassword()
{
$user = User::whereEmail($data['email'])->first();
$user->password = bcrypt($data['new_password']);
$user->save();
}
}
正确:在 findPassword 里面再次验证完成邮箱校验的账户是否为当前找回密码的账号
class UserController extends Controller{ public function check($data)
{
if (checkEmail($data['email'], $data['code'])) {
return true;
}
...
} public function findPassword($data)
{
if (checkEmail($data['email'], $data['code'])) {
$user = User::whereEmail($data['email'])->first();
$user->password = $data['new_password'];
$user->save();
}
...
}
}
限制分页条目范围,防止恶意请求
如获文章列表的接口 localhost/api/articles
public function index($params){
$pageId = $params['pageid'] ?? PAGE_ID; //页码
$pageSize = $params['pagesize'] ?? 15; //条码 $articles = Article::where(function ($query) use ($params) {
...
})->take($pageSize)->skip($pageId * $pageSize)->orderby('id', 'desc')->get();
...
...
}
以上代码如果没有限制 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目录下,然后通过根目录执行这个文件。
需要设计安全的文件上传功能避免上述问题
- 文件上传的目录设置为不可执行
- 判断文件类型
- 使用随机数改写文件名和文件路径
- 单独设置文件服务器的域名
禁止或者避免写自动解压.zip 等压缩文件的代码
单纯地限制文件或压缩包大小并没有用,一个ZIP炸弹的.zip文件仅有 42 KB,但在解压后会占用 4718592 GB
避免登录密码被暴力破解
- 设定严格的速率限制,如登录次数限制,登录错误次数达 x 次时暂停登录 n 分钟
- 密码加上随机盐
public function reg(){
$user = new User;
$salt = radom(6);
$user->password = bcrypt($data['password'] . $salt);
...
}
做好异常处理,避免在生产环境中不正确的错误报告暴露敏感数据
如果你不小心,可能会在生产环境中因为不正确的错误报告泄露了敏感信息,例如:文件夹结构、数据库结构、连接信息与用户信息。
- 在.env 文件中关闭调试模式
APP_DEBUG=true - 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">销毁账户</a>
如果某个用户评论:
<img src=”http://your-website.com/delete-account”> wow
用户将在查看此评论的时候删除他们的账号。
laravel 的 web 路由默认开启了 csrf 验证,原理是在客户端产生一个随机的 token,在表单校验时判断这个 token 是否是这个页面上的请求
PHP代码安全有必要了解下的更多相关文章
- 抓取oschina上面的代码分享python块区下的 标题和对应URL
# -*- coding=utf-8 -*- import requests,re from lxml import etree import sys reload(sys) sys.setdefau ...
- 代码实现PHP web服务器下绝对路径到Web网址的转换
代码实现PHP web服务器下绝对路径到Web网址的转换 代码中用到几个系统变量或常量: 1. 路径中各目录分隔字符 DIRECTORY_SEPARATOR(常量),Windows下DIRECTORY ...
- 流程控制:顺序结构: 代码默认从上到下依次执行 分支结构: 细分在分为如下 循环结构: while .. for ..
# ### 流程控制: ''' 流程: 代码执行的过程 流程控制: 对代码执行的过程进行管控 顺序结构: 代码默认从上到下依次执行 分支结构: 细分在分为如下 循环结构: while .. for . ...
- JAVA代码设置selector不同状态下的背景
Selector设置button点击效果(详细)以及常见问题https://www.jianshu.com/p/a0ddba6d7969 Android 代码动态设置TextView的背景.颜色Sel ...
- 微信小程序富文本渲染组件html2wxml及html2wxml代码块格式化在ios下字体过大问题
1.组件使用: 之前微信小程序的富文本渲染组件用的wxParse,对普通富文本确实可以,但是对于代码格式pre标签则无法使用. 下面这个html2wxml很不错,可以支持代码高亮. 详细文档:http ...
- 去掉VS2010代码中文注释的红色下划线
VS2010代码中文注释出现红色下划线,代码看上去很不美观,发现是由于安装Visual Assist X插件造成的. 解决办法:打开VAX的Options对话框,取消Advanced --> U ...
- git远程代码库回滚(webstorm下)
git远程代码库回滚(webstorm下) 1. 场景 添加了一个文件[file-for-test.js]到git的控制下 进行了三次修改,并分别进行了三次commit,最后进行了一次push git ...
- 三、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Mvvm的08-12示例
这一篇是学习了前2篇RegionManager关联视图,和通过不同的方式加载Module示例之后的开始进入MVVM了. 从第08示例开始,进入了MVVM部分. 从08示例开始学习Prism下的MVVM ...
- 四、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Mvvm的13示例
上一篇之分析了示例,没有最终写DEMO,把这一篇分析完,总结后一起写Prism下的MVVM例子. 这一篇开始分析从13示例开始,分析到MVVM主要部分结束然后写一个分析后的总结DEMO 添加一段新的内 ...
- Using NuGet without committing packages to source control(在没有把包包提交到代码管理器的情况下使用NuGet进行还原 )
外国老用的语言就是谨慎,连场景都限定好了,其实我们经常下载到有用NuGet引用包包然而却没法编译的情况,上谷歌百度搜又没法使用准确的关键字,最多能用到的就是nuget跟packages.config, ...
随机推荐
- ASP.NET Core MVC/API(一)
ASP.NET Core MVC/API(一) 文件夹说明 Pages文件夹:包括了Razor页面和支持文件 .cshtml文件:是使用了Razor语法的C#代码的HTML页面 .cshtml.cs文 ...
- Qt5教程: (3) 自定义信号与槽
1. 自定义槽 槽可以是任何成员函数.普通全局函数.静态函数 槽函数和信号的参数和返回值要一致 由于信号是没有返回值的, 槽函数也一定没有返回值 首先在mainwidget.h中添加槽函数: publ ...
- PHP ksort
1.例子一: <?php /** * 根据 c1 对元素排序 */ $arrays = [ 'b' => [ 'c1' => 10, 'c2' => 5, ], 'a' =&g ...
- Cocos2d-x 学习笔记(23) 分辨率与屏幕适配
Cocos2d-x的分辨率可以分为两种:屏幕分辨率和设计分辨率. 屏幕分辨率就是屏幕窗口的大小,单位是像素. 设计分辨率单位是点,一个点可能包括多个像素. 如果把一台显示器自身的分辨率比作屏幕分辨率的 ...
- 详解AJAX工作原理以及实例讲解(通俗易懂)
什么是 AJAX ? AJAX = 异步 JavaScript 和 XML. AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味 ...
- xshell rz commend not found
sudo apt-get install lrzsz 上传rz 下载sz
- 学习python3高阶函数笔记和demo
python的高阶函数的定义是:一个函数接收另一个函数作为参数,这种函数就称之为高阶函数 举一个最简单的例子: def text(a,b,c): return c(a)+c(b) print( tex ...
- Lab_1:练习一——理解通过make生成执行文件的过程
参考网站: https://www.cnblogs.com/chaunceyctx/p/7188779.html https://cloud.tencent.com/developer/article ...
- LeetCode 84--柱状图中最大的矩形( Largest Rectangle in Histogram) 85--最大矩形(Maximal Rectangle)
84题和85五题 基本是一样的,先说84题 84--柱状图中最大的矩形( Largest Rectangle in Histogram) 思路很简单,通过循环,分别判断第 i 个柱子能够延展的长度le ...
- 设计模式(五)Singleton模式
Singleton模式就是确保只生成一个实例的模式.这里有两个意思,即想确保任何情况下都绝对只有一个实例和想在程序上表现出“只存在一个实例”. 下面通过一个实例来说明这种设计模式. package B ...