热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ThinkPHP安全开发规范

 常见安全问题目前ThinkPHP在国内中小型开发场景非常流行,但由于漏洞频发,主要集中在SQL注入、信息泄露(debug模式打开)、越权等漏洞,使得业务安全性受到不小的挑战。另外由于ThinkPHP

 

常见安全问题

目前ThinkPHP在国内中小型开发场景非常流行,但由于漏洞频发,主要集中在SQL注入、信息泄露(debug模式打开)、越权等漏洞,使得业务安全性受到不小的挑战。另外由于ThinkPHP版本比较多,实际业务多用3.2.3或5.1,因此下面主要从这两个版本来介绍ThinkPHP开发过程中常见的安全问题。


SQL注入

极少业务出现使用官方默认数据库操作方法引发SQL注入的,通常是业务不用官方I函数或者标准方法,而是自定义了过滤函数,例如下面的recursive(),由于采用的黑名单方式过滤不完整且没有对过滤结果二次验证,导致通过双写绕过:

function recursive($arr){
foreach ($arr as $k => $v) {
if (is_array($v)) {
$arr[$k]=recursive($v);
} else {
$keyword = 'select|insert|update|delete|union|into|load_file|outfile|sleep| or ';
$arr1 = explode( '|', $keyword );
$v = str_ireplace( $arr1, '', $v );
$arr[$k] = $v;
}
}
return $arr;
}


开启debug模式

外网环境开启debug模式调试,导致报错信息泄露,之前有开发认为开启error_report(0)可以避免信息泄露,然而这个处理方式对ThinkPHP是没用的。

APP_DEBUG => TRUE;

开启该选项后,一旦sql执行出错或者找不到路由,ThinkPHP则将报错路径甚至sql语句全部暴露。


越权

发生越权的情况比较普遍在于操作数据库时没有验证或者合理验证当前用户是否有权限操作,表现为sql操作时没有加上and user_id=session->userid这样的限制或者使用了and user_id=$_GET("user_id")这样的查询方式,前者的问题时没有绑定当前用户,后者的问题时没有从session获取用户身份而从用户可控参数引用。

 

安全规范

针对以上常见的安全漏洞以及ThinkPHP一年爆几次漏洞的现状,建议按照以下规范合理使用。


部署



  • 务必把你的WEB根目录指向public目录而不是应用根目录,并且不要随意更改入口文件的位置。public目录下面不要放除了入口文件和资源文件以外的其它应用文件。



关闭调试模式



  • 无论是本地开发还是生产环境部署,都不建议直接通过修改配置文件的方式开启/关闭调试模式,而应该使用环境变量(本地开发可以通过定义.env文件)。



请求变量过滤



  • 对于ThinkPHP5,框架建议的获取请求变量的方法是Request类的param方法(如非必要不要再使用get或者post方法获取,更不要使用原生的$_GET/$_POST等方法获取)。对于ThinkPHP3,框架建议在引入请求变量前先使用I函数进行过滤。然而,I函数的过滤并不完整,如果用默认I函数过滤的参数直接拼接到sql语句,大概率还是存在sql注入。

    //DEFAULT_FILTER为空
    $filters = isset($filter)?$filter:C('DEFAULT_FILTER');
    ...
    if(is_array($filters)){
    foreach($filters as $filter){
    if(function_exists($filter)) {
    $data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤
    }else{
    $data = filter_var($data,is_int($filter) ? $filter : filter_id($filter));
    if(false === $data) {
    return isset($default) ? $default : null;
    }
    }
    }
    }
    }
    ...
    is_array($data) && array_walk_recursive($data,'think_filter');
    ...
    //think_filter过滤也很有限
    function think_filter(&$value){
    // TODO 其他安全过滤
    // 过滤查询特殊字符
    if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){
    $value .= ' ';
    }
    }


  • 对于ThinkPHP5,对于有明确类型的请求变量,可以在使用param方法的时候使用类型强制转换。

  • 对于ThinkPHP5,如果需要获取多个数据,建议使用only方法指定需要获取的变量名称,避免有些不怀好意的数据提交导致权限问题。

  • 对于ThinkPHP5,当你使用数据库或者模型操作写入数据的时候,也可以指定字段,避免非法和不希望的字段写入数据库。



上传检测



  • 系统的think\File类提供了文件上传的安全支持,包括对文件后缀、文件类型、文件大小以及上传图片文件的合法性检查。



SQL注入



  • default_filter过滤规则(默认没有任何过滤规则)

  • ThinkPHP的查询统一使用了PDO的prepare预查询和参数绑定机制,能有效的避免SQL注入的发生。但不代表绝对安全,如果你缺乏良好的代码规范,仍然有可能被利用。

  • 一般使用官方提供的标准数据库操作函数即可
    例如ThinkPHP3:

    //标准方式
    $User = M("User"); // 实例化User对象
    $data = $User->where('status=1 AND name="thinkphp"')->find();//如果where条件使用拼接参数则仍存在sql注入
    //原生方式
    $Model = new \Think\Model() // 实例化一个model对象 没有对应任何数据表
    $Model->query("select * from think_user where status=1");


例如ThinkPHP5:

//标准方式
Db::table('think_user')->where('id',1)->find();
//原生方式
Db::query("select * from think_user where id=? AND status=?", [8, 1]);
Db::execute("update think_user set name=:name where status=:status", ['name' => 'thinkphp', 'status' => 1]);


  • 针对ThinkPHP3的I函数需要特别说明,其默认的过滤方法是htmlspecialchars,用于xss防御是足够的,但是对于sql注入而言,则远远不够,理由上面也介绍过了。

  • 对于一些字符串的查询条件(包括原生查询)或者特殊的查询(包括Order部分),需要手动进行参数绑定,官方文档也有介绍。
    thinkphp3

    //手动绑定
    $Model = M('User');
    $where['name'] = ':name';
    $list = $Model->where($where)->bind(':name',I('name'))->select();
    //自动绑定
    $Model = M('User');
    $Model->name = 'thinkphp';
    $Model->email = 'thinkphp@qq.com';
    $Model->add();

    thinkphp5

    //手动绑定
    Db::query("select * from think_user where id=? AND status=?", [8, 1]);
    //自动绑定
    Db::table('think_user')
    ->where('name|title','like','thinkphp%')
    ->where('create_time&update_time','>',0)
    ->find();


  • 另外,如果确实需要自定义函数进行过滤,也应采用白名单的方式而不是黑名单



使用验证器



  • 对于大量的表单需要验证的情况,建议使用验证器功能统一进行数据的合规验证。验证器的验证操作应该在控制器或者路由阶段使用validate方法进行处理。



XSS攻击



  • 如果是5.1版本的话,所有的输出都已经经过了htmlentities 转义输出,确保安全。



CSRF



  • 开启表单令牌验证,尽量开启强制路由并严格规范每个URL请求,定义单独的MISS路由规则。



会话劫持



  • 在每次会话启动的时候,调用regenerate方法。

  • 开启安全头部:更改session配置参数



及时升级安全版本



  • 关注官方微信公众号或开发者周刊可及时了解

















大版本安全建议版本
3.23.2.4+
5.15.1.25+


业务逻辑安全



  • 很多漏洞源于某个业务逻辑自身的安全隐患,包括没有做合理的数据验证和权限检查,尤其是涉及资金及财务层面的,一定要做更多的安全检查,并且开启事务。

  • 一个好的建议是更多的对应用进行分层设计,减少每层的复杂性,独立的分层设计便于提高安全性。

  • 越权:自动完成规则里没有包含数据表中某个字段,遇上调用 create 方法后保存的时候就会引起越权,比如用户表中admin代表用户是否管理员,$_auto没有引入admin字段则可以越权,其他操作也类似。敏感读写操作应加上当前用户身份认证与权限判断。

    $score = ScoreOrder::where('id', $orderId)
    ->where('user_id', $this->uid)
    ->find();


  • 并发:对于资金或资格相关的功能,操作数据时需要加上并发锁,避免通过并发绕过限制。

 

参考



  • ThinkPHP从漏洞挖掘到安全防御

  • ThinkPHP3.2.3安全手册

  • ThinkPHP5.1安全手册

  • ThinkPHP5安全规范指引

  • 开发PHP商城要注意的一些常见安全问题

  • CI框架安全过滤

  • PHP字符串安全过滤函数汇总,防止SQL注入、XSS攻击

  • PHP应用程序安全设计指北



推荐阅读
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • 腾讯安全平台部招聘安全工程师和数据分析工程师
    腾讯安全平台部正在招聘安全工程师和数据分析工程师。安全工程师负责安全问题和安全事件的跟踪和分析,提供安全测试技术支持;数据分析工程师负责安全产品相关系统数据统计和分析挖掘,通过用户行为数据建模为业务决策提供参考。招聘要求包括熟悉渗透测试和常见安全工具原理,精通Web漏洞,熟练使用多门编程语言等。有相关工作经验和在安全站点发表作品的候选人优先考虑。 ... [详细]
  • 本文介绍了Windows Vista操作系统中的用户账户保护功能,该功能是为了增强系统的安全性而设计的。通过对Vista测试版的体验,可以看到系统在安全性方面的进步。该功能的引入,为用户的账户安全提供了更好的保障。 ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
author-avatar
潇洒嘉新
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有