PHP防SQL注入学习

该示例在MySQL8.0 + PHP7.3 + ThinkPHP5下操作

前提条件:

1.配置文件config.php中默认全局过滤方法

// 默认全局过滤方法 用逗号分隔多个
'default_filter'         => '',

2.创建test表

3.创建test控制器

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Test extends Controller
{

    public function index(){
        if(input('post.')){
            $data = [
                'content' => input('post.content'),
            ];
            $result = Db::table('test')->insert($data);
            if($result){
                dump("add suc");
            }
        }
        $list = Db::table('test')->select();
        $this->assign('list',$list);
        return $this->fetch('index/test');
    }
}

4.创建test模板

{include file="index/head" /}
<form role="form" action="{:url('Test/index')}" method="post">
    <div class="form-group">
        <label>内容</label>
        <textarea class="form-control" name="content" rows="3"></textarea>
    </div>
    <button type="submit" class="btn btn-default">提交</button>
</form>
{volist name="list" id="vo"}
<p>{$vo.content}</p>
{/volist}
</body>
</html>

页面效果:

学习开始

addslashes()函数,会对单引号、双引号、反斜杠进行转义过滤

默认情况下,PHP会对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes(),如果对已转义过的字符串使用 addslashes(),会导致双层转义,所以需要借助get_magic_quotes_gpc()函数进行检测。

代码修改如下

public function index(){
    if(get_magic_quotes_gpc()){
        dump("open");
    }else{
        dump("close");
    }

    if(input('post.')){
        $data = [
            'content' => input('post.content'),
        ];
        $result = Db::table('test')->insert($data);
        if($result){
            dump("add suc");
        }
    }
    $list = Db::table('test')->select();
    $this->assign('list',$list);
    return $this->fetch('index/test');
}

页面效果如下

get_magic_quotes_gpc()未开启,所以需要addslashes()过滤传参

先看没有用addslashes()过滤的传参

依次在输入框输入

‘这是一条测试语句’
“这是一条测试语句”
'这是一条测试语句'
"这是一条测试语句"
\这是一条测试语句\

数据表数据如下

页面效果如下

接下来对传参过滤

$data = [
    'content' => addslashes(input('post.content')),
];

重复上述传参,下面是addslashes()过滤后的效果

数据库数据展示

页面效果

htmlspecialchars() 函数 将字符 “<” (小于)和 “>” (大于)转换为 HTML 实体

先看没有用htmlspecialchars()转义的传参效果

在输入框输入

<b>这是一条测试语句</b>

数据表数据如下

页面效果如下

现在使用htmlspecialchars()转义

$data = [
'content' => htmlspecialchars(input('post.content')),
];

数据如下

页面效果如下

strip_tags() 函数 会剥去字符串中的 HTML 标签

同样先看没用strip_tags()前的效果

输入框输入

<b>这是一条测试语句</b>

数据表如下

页面效果如下

使用strip_tags()后的效果

$data = [
'content' => strip_tags(input('post.content')),
];

数据表如下

页面效果如下

 nl2br() 函数 在字符串中的新行(\n)之前插入换行符

先看没用nl2br()前的效果

输入框输入

数据表如下

页面效果如下

下面是使用nl2br()后的效果

$data = [
'content' => nl2br(input('post.content')),
];

数据表数据

页面效果

addcslashes() 函数 在指定的字符前添加反斜杠

addcslashes()addslashes()作用类似,却不相同,常用在查询数据表的情况下

先在输入框输入以下参数

这是一条测试参数
这是一条测试%参数
这是一条测试_参数

数据表

页面效果

现在对上述数据进行like查询,修改代码

$list = Db::table('test')->select();
$this->assign('list',$list);

$content = '测试%';
$content = '%'.$content.'%';
$search = Db::table('test')->where(['content'=>['like',$content]])->select();
$this->assign('search',$search);
{volist name="list" id="vo"}
<p>{$vo.content}</p>
{/volist}
<p>--------------------磕碜的分割线-----------------------</p>
{volist name="search" id="vo"}
<p>{$vo.content}</p>
{/volist}

页面效果如下

本意是查找测试%的,结果却将数据表的数据全查询出来的。

//查询条件修改如下,效果依旧如上所示
$content = '%测试_%';

总之数据中存在下划线或百分号,查询数据就会出现问题

现在使用addcslashes()重新查询

$content = '测试%';
$content = addcslashes($content,'%_');
$content = '%'.$content.'%';重新like查询

页面效果如下

———————————华丽的分割线————————————–

结合上面所学,创建防sql注入方法

/*
 * 防sql注入
 */
function sql_filter($post)
{
    // 判断magic_quotes_gpc是否为打开
    if (!get_magic_quotes_gpc())
    {
        // magic_quotes_gpc没有打开的情况对提交数据的过滤
        $post = addslashes($post);
    }
    $post = addcslashes($post, '%_');  //%_过滤
    $post = htmlspecialchars($post); // html标记转换
    $post = nl2br($post); // 回车转换
    $post = strip_tags($post);
    return $post;
}

上述防注入方法仅供参考,还请贴合自身网站使用