如何使用PDO防护含GET参数拼接的PHP SQL查询免受SQL注入?
使用PDO修复IN条件的SQL注入风险
你的代码直接把zeme和kraj参数拼进SQL的IN子句,哪怕替换了%2C也完全挡不住SQL注入——攻击者可以轻松构造恶意参数篡改查询逻辑,甚至获取敏感数据。下面是修复方案,全程用PDO参数绑定来规避风险:
步骤1:安全处理用户输入并生成占位符
首先,我们需要把用户传入的逗号分隔值拆分成数组,过滤掉无效值(假设zeme和kraj都是整数ID),然后为每个有效值生成对应的占位符:
$params = []; // 存储所有要绑定的参数 $podminkazeme = ""; $podminkakraj = ""; // 处理zeme参数 if (isset($_GET["zeme"]) && !empty($_GET["zeme"])) { // 拆分逗号分隔的值($_GET已经自动解码,无需额外处理%2C) $zemeValues = explode(',', $_GET["zeme"]); // 过滤为整数,避免非数字注入 $zemeValues = array_map('intval', $zemeValues); // 移除空值 $zemeValues = array_filter($zemeValues); if (!empty($zemeValues)) { // 生成对应数量的命名占位符 $placeholders = []; foreach ($zemeValues as $index => $value) { $key = ":zeme_" . ($index + 1); $placeholders[] = $key; $params[$key] = $value; } $podminkazeme = "and nb.zemehledani in (" . implode(', ', $placeholders) . ")"; } } // 处理kraj参数,逻辑和zeme一致 if (isset($_GET["kraj"]) && !empty($_GET["kraj"])) { $krajValues = explode(',', $_GET["kraj"]); $krajValues = array_map('intval', $krajValues); $krajValues = array_filter($krajValues); if (!empty($krajValues)) { $placeholders = []; foreach ($krajValues as $index => $value) { $key = ":kraj_" . ($index + 1); $placeholders[] = $key; $params[$key] = $value; } $podminkakraj = "and nb.krajhledani in (" . implode(', ', $placeholders) . ")"; } }
步骤2:执行预处理语句
保持原有的SQL拼接逻辑,但执行时传入参数数组:
$conn = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD); // 开启PDO异常模式,方便调试 $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sqljednotkaa = " select nb.*, dv.nazev as developer, UNIX_TIMESTAMP(nb.datumAktualizace) as datumAktualizace, UNIX_TIMESTAMP(nb.datumPripomenuti) as datumPripomenuti, uz.nazev as skladUpravil, uzm.nazev as makler, tp.nazev as typProdeje, dal.nazev as nazevdalnice from nabidka nb left join uzivatele uz on uz.id=nb.skladUpravil left join uzivatele uzm on uzm.id=nb.makler left join typProdeje tp on tp.id=nb.typProdeje left join developer dv on dv.id=nb.developer left join dalnice dal on dal.id=nb.dalnice where nb.emptyid is null $podminkaid $podminkastav $podminkaupraveno $podminkavelikost $podminkacena $podminkamakler $podminkaexport $podminkatypprodeje $podminkatypnemovitosti $podminkazeme $podminkadalnice $podminkakraj $podminkaokres $podminkadeveloper $podminkatechnickeparametry $podminkahledanislovo order by nb.emptyid asc $razenipodminka"; $stjednotkaa = $conn->prepare($sqljednotkaa); // 传入参数数组执行预处理语句 $stjednotkaa->execute($params);
关键注意点
- 不要依赖字符串替换防护注入:哪怕替换了逗号,攻击者仍可传入
1); DROP TABLE nabidka;--这类恶意值,直接替换完全无效。 - 验证输入类型:如果
zeme和kraj是字符串(比如国家代码),可改用trim()过滤或正则验证格式,再绑定参数。 - 异常模式调试:开启
ERRMODE_EXCEPTION能快速定位SQL执行中的问题,上线后可根据需求调整错误处理逻辑。
内容的提问来源于stack exchange,提问作者strejcekmichal
相关产品推荐
相关产品推荐

