You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

WordPress自定义插件SQL注入防护:WPDB安全实现方法咨询

如何在WordPress插件中防范SQL注入

首先明确回答你的问题:WordPress完全支持预处理语句,而且官方推荐使用$wpdb类提供的安全方法来处理数据库操作,从根源上避免SQL注入风险。你原代码的问题在于直接将用户输入的变量拼接进SQL语句,这是典型的注入风险点,下面结合你的代码一步步修改:

问题代码的风险分析

你原代码中的SELECTINSERT语句都是直接把$_POST里的变量拼进SQL:

$check_data = $wpdb->get_results("SELECT * FROM ".$tablename." WHERE username='".$uname."' ");
$insert_sql = "INSERT INTO ".$tablename."(name,username,email) values('".$name."','".$uname."','".$email."') ";

如果用户输入类似' OR 1=1 --这样的内容,就能轻松绕过查询逻辑甚至篡改数据。

方法1:使用$wpdb->prepare()预处理语句

$wpdb->prepare()是WordPress官方推荐的安全方法,它会自动为你的变量添加转义,并支持占位符(%s字符串、%d整数、%f浮点数),用法如下:

global $wpdb; 
// Add record 
if(isset($_POST['submit'])){ 
    $name = sanitize_text_field($_POST['txt_name']); // 先做前端输入清洗
    $uname = sanitize_text_field($_POST['txt_uname']);
    $email = sanitize_email($_POST['txt_email']);
    $tablename = $wpdb->prefix . "myplugin"; 

    if(!empty($name) && !empty($uname) && !empty($email)){ 
        // 用prepare处理SELECT查询
        $check_query = $wpdb->prepare(
            "SELECT * FROM %i WHERE username = %s",
            $tablename,
            $uname
        );
        $check_data = $wpdb->get_results($check_query); 

        if(count($check_data) == 0){ 
            // 用prepare处理INSERT语句
            $insert_query = $wpdb->prepare(
                "INSERT INTO %i (name, username, email) VALUES (%s, %s, %s)",
                $tablename,
                $name,
                $uname,
                $email
            );
            $wpdb->query($insert_query); 
            echo "Save successfully."; 
        } 
    }
}

这里注意:

  • %i是专门用于表名/字段名的占位符,普通变量用%s对应字符串类型
  • 先通过sanitize_text_field()sanitize_email()对用户输入做初步清洗,这是额外的安全层

方法2:使用$wpdb->insert()简化插入操作

WordPress还提供了更便捷的$wpdb->insert()方法,它内部已经自动处理了转义和预处理,代码更简洁:

global $wpdb; 
// Add record 
if(isset($_POST['submit'])){ 
    $name = sanitize_text_field($_POST['txt_name']);
    $uname = sanitize_text_field($_POST['txt_uname']);
    $email = sanitize_email($_POST['txt_email']);
    $tablename = $wpdb->prefix . "myplugin"; 

    if(!empty($name) && !empty($uname) && !empty($email)){ 
        // 查询部分依然用prepare
        $check_query = $wpdb->prepare(
            "SELECT * FROM %i WHERE username = %s",
            $tablename,
            $uname
        );
        $check_data = $wpdb->get_results($check_query); 

        if(count($check_data) == 0){ 
            // 使用insert方法,自动处理安全
            $insert_result = $wpdb->insert(
                $tablename,
                array(
                    'name' => $name,
                    'username' => $uname,
                    'email' => $email
                ),
                array(
                    '%s', // name的类型
                    '%s', // username的类型
                    '%s'  // email的类型
                )
            );
            if($insert_result){
                echo "Save successfully."; 
            } else {
                echo "Error saving data.";
            }
        } 
    }
}

$wpdb->insert()的第二个参数是要插入的键值对数组,第三个参数是对应每个字段的数据类型占位符,它会自动帮你完成预处理和转义,不用手动写SQL语句,减少出错概率。

额外安全建议

  • 永远不要信任用户输入:除了用WordPress的安全方法处理数据库操作,还要对输入做类型校验和清洗
  • 避免直接使用$wpdb->query()执行拼接的SQL语句,除非你已经用prepare()处理过
  • 可以开启WordPress的调试模式(WP_DEBUG),开发时能及时发现数据库操作的错误

内容的提问来源于stack exchange,提问作者jmarkatti

火山引擎 最新活动