代码安全
开发安全是我们在开发过程中很容易的一个环节,由于程序的不严谨很容易数据泄漏、数据丢失、服务器被提权,因此我们在开发过程中就要尽量做到开发规范严谨,接下来主要讲解下在开发过程中要注意避免产生BUG的几种情形
SQL注入
这种问题常常出现在读写操作数据库时产生,很多时候我们需要查询数据库的数据做逻辑操作,由于未对请求的参数做过滤或处理,很容易产生数据丢失和数据泄漏的问题。
例如,我们需要根据用户名查询指定用户的信息,我们常用的SQL语句如下:
$username = $this->request->request("username");
\think\Db::query("SELECT * FROM fa_user WHERE username='{$username}'");
一般情况下我们username
参数传普通参数都不会有问题,但是如果遇到别有用心之人传一些特殊参数,例如传递username
的参数为
http://www.yoursite.com/test/index?username=' OR '1'='1
此时我们接收到的username
为' OR '1'='1
,最终生成的SQL语句为
SELECT * FROM fa_user WHERE username='' OR '1'='1'
此时将导致筛选所有数据或筛选我们任意想要的数据。
那如果避免这种情况发生呢?我们有以下几种解决方法
1、使用参数预处理
$username = $this->request->request("username", "");
$username = htmlspecialchars($username, ENT_QUOTES);
\think\Db::query("SELECT * FROM fa_user WHERE username=:username", ['username'=>$username]);
2、使用模型的自带的查询方法进行查询
$username = $this->request->request("username", "");
$username = htmlspecialchars($username, ENT_QUOTES);
//方法1
\app\common\model\User::getByUsername($username);
//方法2
\app\common\model\User::where('username', $username)->find();
在ThinkPHP5中提供了许多数据输入过滤方法,例如
//强制转换为Email格式
$this->request->post('email','',FILTER_VALIDATE_EMAIL);
$this->request->post('email','','email');
//强制转换为数字
$this->request->post('id/d','0');
常用的修饰符如下
修饰符 | 作用 |
---|---|
s | 强制转换为字符串类型 |
d | 强制转换为整型类型 |
b | 强制转换为布尔类型 |
a | 强制转换为数组类型 |
f | 强制转换为浮点类型 |
XSS跨站注入
XSS跨站点脚本注入常常出现在浏览器客户端输出时由于未对输出的数据进行过滤和转换,导致浏览器响应执行了Javascript代码,这个代码代具有管理员权限的用户做一些隐藏的操作,比如提权、恶意修改删除数据,甚至将用户当前浏览器端的Cookie等数据传到攻击者的服务器,攻击者通过伪造Cookie请求,很容易造成用户信息漏洞和数据丢失的情况。这种问题常出现在会员昵称、会员头像输出、会员评论数据等情况下。
解决防范XSS跨站注入的首先是按照上方的SQL注入做好请求数据过滤,其次是做好数据输出时的编码,我们在视图模板中编写代码时,可以通过添加htmlentities
对HTML代码做实体编码,例如
<input type="text" name="username" value="{$username|htmlentities}" />
千万不要直接使用以下的代码,以下代码都是非常不安全的
<input type="text" name="username" value="{$Think.get.username}" />
或
<input type="text" name="username" value="{$_GET['username']}" />
CSRF跨站请求
CSRF全称为cross site request forgery
,中文意思为:跨站点伪装请求
。
跨站点请求的原理就是用户A
在站点1
发布上传粘贴了一个站点2
的URL,用户B
不明就里的点击了站点2
的URL,而这个URL因为是伪装请求站点1
修改密码(其它危险请求)的操作。此时用户A
就已经获取了用户B
的账户信息。
例如我们常常在编写表单提交的时候都是如下的写法
<form action="">
<input type="password" name="newpassword" />
<input type="submit" />
</form>
以上的写法很容易产生CSRF跨站点伪装请求。
在ThinkPHP5可以很方便的使用token
的方式来防范这种威胁,比如我们将上面的代码改写为
<form action="">
{:token()}
<input type="password" name="newpassword" />
<input type="submit" />
</form>
我们添加了一个{:token()}
,由于这个token是我们服务端动态输出的,伪装者的服务器没法获取该值,此时我们再做好服务端验证这个token
是否有效即可,常用的方法如下
$token = $this->request->post('__token__');
//验证Token
if (!$token || !\think\Validate::is($token, "token", ['__token__' => $token])) {
$this->error("请勿非常请求");
}
更多Token表单令牌的使用方法可以参考ThinkPHP5官方文档:https://www.kancloud.cn/manual/thinkphp5/193918