我的CMS代码是否存在SQL注入漏洞?求安全检测
你的CMS代码SQL注入风险分析&优化建议
嘿,咱们来仔细拆解下你这段代码的情况:首先得给你吃个定心丸——你已经用了预处理语句(prepare + bind_param),这是防范SQL注入的黄金方案,核心的插入逻辑是安全的,不会存在SQL注入漏洞。不过代码里藏着不少小问题,可能导致数据异常或者逻辑出错,下面给你逐一梳理:
一、代码里的主要问题
- 变量覆盖的低级错误:你处理
$distrct(用户提交的地区字段)之后,居然把$division的处理结果又赋值给了$distrct!这直接导致用户提交的地区数据被覆盖,最后插入数据库的其实是分区(division)的值,完全不符合你的需求:$distrct = $_POST['distrct']; $distrct = strip_tags($distrct); $distrct = htmlentities($distrct); $distrct = mysqli_real_escape_string($con, $distrct); // 下面这三行全错了!应该给$division赋值,不是覆盖$distrct $division = $_POST['division']; $distrct = strip_tags($division); $distrct = htmlentities($division); $distrct = mysqli_real_escape_string($con, $division); - 多余的转义/过滤操作:既然用了预处理语句,
bind_param会自动帮你处理参数的转义,根本不需要额外调用strip_tags、htmlentities、mysqli_real_escape_string。尤其是htmlentities会把<、>这类特殊字符转成HTML实体,存进数据库后,要是取出来不转回来,显示的就是<这种奇怪的字符,严重影响内容正常展示。 - 主键处理不够合理:如果
couts表的id是自增主键,你完全不需要手动传NULL,直接在INSERT语句里删掉id列就行,数据库会自动帮你生成主键值:
另外你绑定参数用的是INSERT INTO couts (name, distrct, division) VALUES(?,?,?)'ssss'(四个字符串类型),但$id是NULL,虽然MySQL可能会自动转换,但严谨点的话,不需要传的字段就别放进SQL语句里。 - 字符集设置的语法错误:你设置SESSION排序规则的语句写错了:
正确的写法应该是这样:mysqli_query($con, "SET SESSION collation collation='utf8_general_ci'");// 更简洁的方式设置字符集和排序规则 mysqli_set_charset($con, 'utf8'); // 或者单独设置排序规则 mysqli_query($con, "SET SESSION collation_connection = 'utf8_general_ci'"); - 完全没做错误处理:代码里没有检查
prepare、bind_param、execute是否成功,要是数据库连接失败、SQL语句写错,直接就会抛出错误,既不友好也不利于排查问题。
二、优化后的安全代码示例
if(isset($_POST['cout'])){ $servername = "localhost"; $username = "root"; $password = ""; $db = "bangla"; // 创建连接并检查连接状态 $con = new mysqli($servername, $username, $password, $db); if ($con->connect_error) { die("数据库连接失败: " . $con->connect_error); } // 设置字符集(推荐用这种简洁方式) mysqli_set_charset($con, 'utf8'); // 获取用户输入,用??语法避免未定义索引错误 $name = $_POST['name'] ?? ''; $distrct = $_POST['distrct'] ?? ''; $division = $_POST['division'] ?? ''; // 预处理SQL语句(省略自增主键id) $stmt = $con->prepare("INSERT INTO couts (name, distrct, division) VALUES(?,?,?)"); if (!$stmt) { die("预处理SQL失败: " . $con->error); } // 绑定参数:s代表字符串类型,如果字段是整数可以用i,根据实际表结构调整 $stmt->bind_param('sss', $name, $distrct, $division); if (!$stmt->execute()) { die("执行插入失败: " . $stmt->error); } echo "新记录创建成功"; // 记得关闭语句和连接,养成好习惯 $stmt->close(); $con->close(); }
三、防范SQL注入的核心要点
- 死磕预处理语句:这是目前最可靠的防注入手段,绝对不要把用户输入直接拼进SQL语句里,哪怕你觉得转义过也不行。
- 别依赖转义函数:
mysqli_real_escape_string这类函数只能应付简单场景,稍微复杂一点的输入就可能出问题,预处理才是王道。 - 一定要做输入验证:虽然预处理能防注入,但还是要对用户输入做合法性检查(比如检查长度、格式是否符合要求),别什么脏数据都往数据库里塞。
- 数据库权限最小化:连接数据库的用户只给必要的权限(比如INSERT、SELECT),别用root这种超级权限用户,就算真出了漏洞,也能把危害降到最低。
内容的提问来源于stack exchange,提问作者Shamol Singha Extr




