服务端字符过滤 与 SQL PDO防注入

注入示例

复制代码
# step 1 SQL
SELECT * FROM users WHERE username = 'admin' AND password = 'e10adc3949ba59abbe56e057f20f883e'
# step 2 SQL
SELECT * FROM users WHERE username = 'admin'#' AND password = '96e79218965eb72c92a549dd5a330112'

关键点是这2个SQL的区别.其中第二步由于前台传入特殊字符单引号(')及#,在数据库中#为语句注释部分,则后续SQL语句不会被执行,可直接跳过我们的密码验证逻辑。

username还可以是 'admin' OR 1='1 跳过验证

1. PHP端防注入

++1.1 字符型过滤++

复制代码
/*discuz过滤函数*/
function inject_check($sql_str)  
{  
	return preg_match('/^select|insert|and|or|create|update|delete|alter|count|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i', $sql_str); // 进行过滤  
} 

$data[] = $_GET['username'];
$data[] = $_GET['passwd'];
function inject_checks($data) {
    foreach($data as $key => $val){
        if(preg_match('/^select|insert|and|or|create|update|delete|alter|count|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i', $val)){
            return true;
        }
    }
    
    return false;
}

上面是discuz过滤字符型注入的函数 ,返回检测结果,1 or 0

1就是存在特殊字符

示例:

复制代码
if(inject_check($str)){
    exit('非法字符!');
}

foreach($_POST as $key => $value){
    if(inject_check($value)){
        echo '非法字符';
        exit();
    }
}

这种要求比较严格的过滤,一般应用在注册和登陆环节

++1.2 数字型的过滤++

复制代码
$id = intval($_GET['id']);

数字型的就比较简单了。只需要转换一下

++1.3 富文本的过滤++

复制代码
$html = "<a href='test'>Test</a>";
$html = addslashes($html);

输出:

<a href=\'test\'>Test</a>

需要显示的时候再用 stripslashes 处理

复制代码

++1.4 统一转义++

复制代码
if (!get_magic_quotes_gpc())
{
    if (!empty($_GET))
    {
        $_GET  = addslashes_deep($_GET);
    }
    if (!empty($_POST))
    {
        $_POST = addslashes_deep($_POST);
    }

    $_COOKIE   = addslashes_deep($_COOKIE);
    $_REQUEST  = addslashes_deep($_REQUEST);
}

function addslashes_deep($value)
{
    if (empty($value))
    {
        return $value;
    }
    else
    {
        return is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
    }
}
复制代码

array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。

这样数组中的每个值都得到转义处理

2. PDO方式防止注入

pdo中的预处理语句

复制代码
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "haha";
 
try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    // 设置 PDO 错误模式为异常
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
    // 预处理 SQL 并绑定参数
    $stmt = $conn->prepare("select * from dw_user where `username`=:username and `password`=:password");
    $stmt->bindParam(':username', $firstname);
	$stmt->bindParam(':password', $pass);

    // 插入行
    $firstname = $_POST['username'];
	$pass = $_POST['password'];
    //$lastname = "Doe";
    //$email = "john@example.com";
    $stmt->execute();
    $rs = $stmt->Fetch();
	if($rs['user_id'] > 0 ){
		echo '登陆成功!';
		exit();
	}else{
		echo '登陆失败!';
		exit();
	}
 
    // 插入其他行
    //$firstname = "Mary";
    //$lastname = "Moe";
    //$email = "mary@example.com";
    //$stmt->execute();
 
    // 插入其他行
    //$firstname = "Julie";
    //$lastname = "Dooley";
    //$email = "julie@example.com";
    //$stmt->execute();
 
    //echo "新记录插入成功";
}
catch(PDOException $e)
{
    echo "Error: " . $e->getMessage();
}
$conn = null;

预处理绑定 会变成字符串包起来 不是 简单的 SQL 拼接

复制代码
相关推荐
muren17 分钟前
Qt DuckDB SQL 驱动插件
数据库
一匹电信狗42 分钟前
【MySQL】数据库基础
linux·运维·服务器·数据库·mysql·ubuntu·小程序
FL16238631291 小时前
VMware运行python脚本提示libGL error: MESA-LOADER: failed to open swrast
linux·运维·服务器
路由侠内网穿透1 小时前
本地部署开源视频存档和搜索引擎工具 TubeArchivist 并实现外部访问
服务器·网络·windows·tcp/ip·搜索引擎·开源
未来之窗软件服务1 小时前
操作系统应用开发(十四)RustDesk服务器配置——东方仙盟筑基期
运维·服务器·远程桌面·rustdesk·仙盟创梦ide·东方仙盟
LoneEon1 小时前
Ubuntu 部署 ClickHouse:高性能分析型数据库(附shell脚本一键部署↓)
数据库·clickhouse
189228048612 小时前
NX482NX486美光固态闪存NX507NX508
大数据·网络·数据库·人工智能·性能优化
有一个好名字3 小时前
从 3.6 亿订单表到毫秒级查询:分库分表指南
数据库·oracle
ms72wx3 小时前
拥抱终端:Linux 新手命令行入门指南
linux·运维·服务器
wheeldown5 小时前
【Linux】Linux管道与进程池深度解析:从原理到实战
linux·运维·服务器