系统安全
系统安全指ThinkPHP可以配合的服务器的安全部署策略。应用部署建议
首先,我们建议在条件允许的情况下,把框架目录和项目目录都部署在非WEB访问目录下面,ThinkPHP的访问机制完全支持框架和项目的非WEB目录访问,你只需要把入口文件和资源(主要是指JS、样式和图片文件)目录放置于WEB目录下面即可。因此,建议的部署目录如下:
- index.php 项目入口文件
- Public/ 项目资源文件目录
- Js/ JS目录
- Css/ 样式文件目录
- Images/ 图像文件目录
- protected/ (受保护的目录,可以部署到非WEB目录或者设置安全访问)
- ThinkPHP/ 框架系统目录
- App/ 项目目录
- Uploads/ 项目上传目录
复制代码
系统安全设置
如果你已经通过部署策略设置了系统目录安全访问的话,则可以跳过这段。如果你无法完全做到上述的服务器目录安全保护,也无需担心,ThinkPHP仍然可以通过设置确保你的目录安全。框架的核心文件本身已经做了访问判断,所有核心文件均不能直接在URL中被访问,因此也不用担心直接访问某些文件导致的错误暴露你的服务器路径之类的信息。
对于应用目录,系统则提供了目录安全访问机制,你可以在第一次生成项目目录结构之前,在入口文件中添加:
- define('BUILD_DIR_SECURE', true);
复制代码
- define('DIR_SECURE_FILENAME', 'default.html');
复制代码
- define('DIR_SECURE_FILENAME', 'index.html,index.htm');
复制代码
- define('DIR_SECURE_CONTENT', 'deney Access!');
复制代码
- define('BUILD_DIR_SECURE',true);
- define('DIR_SECURE_FILENAME', 'index.html');
- define('DIR_SECURE_CONTENT', 'deney Access!');
复制代码
- <Files *.html>
- Order Allow,Deny
- Deny from all
- </Files>
复制代码
表单安全
自动验证和自动完成
ThinkPHP内置的 自动验证 和 自动完成 功能可以有效地对表单提交的数据安全加以控制。这两部分在快速入门系列中已经有过详细的介绍,就不再描述了。表单令牌
ThinkPHP内置了表单令牌验证功能,可以有效防止表单的重复提交等安全防护。表单令牌验证相关的配置参数有:
- 'TOKEN_ON'=>true, // 是否开启令牌验证 默认关闭
- 'TOKEN_NAME'=>'__hash__', // 令牌验证的表单隐藏字段名称
- 'TOKEN_TYPE'=>'md5', //令牌哈希验证规则 默认为MD5
- 'TOKEN_RESET'=>true, //令牌验证出错后是否重置令牌 默认为true
复制代码
自动生成的隐藏域位于表单Form结束标志之前,如果希望自己控制隐藏域的位置,可以手动在表单页面添加{__TOKEN__} 标识,系统会在输出模板的时候自动替换。
如果页面中存在多个表单,建议添加{__TOKEN__}标识,并确保只有一个表单需要令牌验证。
如果个别页面输出不希望进行表单令牌验证,可以在控制器中的输出方法之前动态关闭表单令牌验证,例如:
- C('TOKEN_ON',false);
- $this->display();
复制代码
- $User = M("User"); // 实例化User对象
- // 手动进行令牌验证
- if (!$User->autoCheckToken($_POST)){
- // 令牌验证错误
- }
复制代码
表单合法性检测
表单合法性检测是3.1版本开始增加的表单提交字段检测机制,你不再需要担心用户在提交表单的时候注入非法字段数据了。表单字段合法性检测需要使用create方法创建数据对象的时候才能生效,有两种方式:一、属性定义
可以给模型配置insertFields 和 updateFields属性用于新增和编辑表单设置,使用create方法创建数据对象的时候,不在定义范围内的属性将直接丢弃,避免表单提交非法数据。insertFields 和 updateFields属性的设置采用字符串(逗号分割多个字段)或者数组的方式,例如:
- class UserModel extends Model{
- protected $insertFields = array('account','password','nickname','email');
- protected $updateFields = array('nickname','email');
- }
复制代码
在使用的时候,我们调用create方法的时候,会根据提交类型自动识别insertFields和updateFields属性:
- D('User')->create();
复制代码
下面是采用字符串定义的方式,同样有效:
- class UserModel extends Model{
- protected $insertFields = 'account,password,nickname,email';
- protected $updateFields = 'nickname,email';
- }
复制代码
二、方法调用
如果不想定义insertFields和updateFields属性,或者希望可以动态调用,可以在调用create方法之前直接调用field方法,例如,实现和上面的例子同样的作用:在新增用户数据的时候,使用:
- $User = M('User');
- $User->field('account,password,nickname,email')->create();
- $User->add();
复制代码
- $User = M('User');
- $User->field('nickname,email')->create();
- $User->where($map)->save();
复制代码
如果你的字段比较多,还可以使用field方法的排除功能,例如:
- $User->field('status,create_time',true)->create();
复制代码
变量安全
变量安全获取
对全局系统变量的获取建议采用系统提供的变量获取方法获取,具体可以参考 快速入门系列的变量全局变量过滤
如果你习惯于直接调用$_GET $_POST变量的话,那么或者可以采用ThinkPHP系统内置的对全局变量的安全过滤方式,只需要设置VAR_FILTERS参数。例如:
- 'VAR_FILTERS'=>'htmlspecialchars'
复制代码
- 'VAR_FILTERS'=>'filter_vars'
复制代码
- function filter_vars(&$value){
- $value = htmlspecialchars($value);
- }
复制代码
数据安全
防SQL注入
对于WEB应用来说,SQL注入攻击无疑是首要防范的安全问题,系统底层对于数据安全方面本身进行了很多的处理和相应的防范机制,例如:
- $User = M("User"); // 实例化User对象
- $User->find($_GET["id"]);
复制代码
即便用户输入了一些恶意的id参数,系统也会强制转换成整型,避免恶意注入。这是因为,系统会对数据进行强制的数据类型检测,并且对数据来源进行数据格式转换。而且,对于字符串类型的数据,ThinkPHP都会进行escape_string处理。
通常的安全隐患在于你的查询条件使用了字符串参数,然后其中一些变量又依赖由客户端的用户输入,要有效的防止SQL注入问题,我们建议:
查询条件尽量使用数组方式,这是更为安全的方式;
如果不得已必须使用字符串查询条件,使用预处理机制;
查询条件预处理
where方法使用字符串条件的时候,支持预处理(安全过滤),并支持两种方式传入预处理参数,例如:
- $Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
复制代码
- $Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
复制代码
- $model->query('select * from user where id=%d and status=%d',$id,$status);
复制代码
- $model->query('select * from user where id=%d and status=%d',array($id,$status));
复制代码
防XSS攻击
XSS(跨站脚本攻击)可以用于窃取其他用户的Cookie信息,要避免此类问题,可以采用如下解决方案:直接过滤所有的JavaScript脚本;
转义Html元字符,使用htmlentities、htmlspecialchars等函数;
系统的扩展函数库提供了XSS安全过滤的remove_xss方法;
新版对URL访问的一些系统变量已经做了XSS处理。
上传安全
网站的上传功能也是一个非常容易被攻击的入口,所以对上传功能的安全检查是尤其必要的。系统提供的上传扩展类库(ORG.Net.UploadFile)提供了安全方面的支持,包括对文件后缀、文件类型、文件大小以及上传图片文件的合法性检查,确保你已经在上传操作中启用了这些合法性检查。
其他安全建议
下面的一些安全建议也是非常重要的:对所有公共的操作方法做必要的安全检查,防止用户通过URL直接调用;
不要缓存需要用户认证的页面;
对于关键操作需要检查用户权限;
对用户的上传文件,做必要的安全检查,例如上传路径和非法格式。
如非必要,不要开启服务器的目录浏览权限;
对于项目进行充分的测试,不要生成业务逻辑的安全隐患(这可能是最大的安全问题);