SELECT * FROM `dict_plugin` limit 20 ,10; SELECT count(*) as totalCount from `dict_plugin`;将会形成2个数据集,golang的实践如下:
results, err = p.Query(querystring) for results.Next() { err = results.Scan(&...) } # 堆代码 duidaima.com if !results.NextResultSet() { log.ErrorF(ctx, "expected more result sets: %v", results.Err()) } for results.Next() { err = results.Scan(&totalCount) }既然提到了开启client_multi_statements 有sql注入的风险,我们就展开聊一聊。
var input_name string query: = "select * from user where user_name='" + input_name+"'" sql.Query(query)如果从界面输入的input_name="janus';delete from user; --",
query:= "select * from user where user='" + input_name +"' and pwd='" +input_pwd +"'" select * from user where user='xxx' and pwd='' OR '1'='1' -- 会绕过认证逻辑。3. 参数化查询防止sql注入
// Correct format for executing an SQL statement with parameters. var queryStr = "SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = ?" var args string = "55 union select * from `dict_plugin_Test`" rows, err := db.Query(queryStr, args)sql查询内部会利用提供的参数1创建预编译语句, 在运行时,实际是执行带参的预编译后的语句。
2024-08-13T08:07:18.922818Z 26 Connect root@localhost on tcinfra_janus_sharing using TCP/IP 2024-08-13T08:07:18.924525Z 26 Prepare SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = ? 2024-08-13T08:07:18.924671Z 26 Execute SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = '55 union select * from `dict_plugin_Test`' 2024-08-13T08:07:18.925273Z 26 Close stmt判断mysql数据库开启了查询日志:show variables like '%general_log%';
服务器返回一个确认响应,表示预编译语句已经成功准备好。
客户端 服务器 | | |----预编译语句(Prepare)------>| | | |<-------确认响应(OK)----------| | | |---执行语句(Execute) + 参数---->| | | |<----------查询结果-------------|我们了解到预编译语句,将SQL语义和数据分离,通过两次sql交互(在预编译阶段固定了sql语义结构), 有效防止了SQL注入攻击, 另一方面,预编译语句在重复执行某一sql语句时确实有加快查询结果的效果。
stmt, err := p.Prepare("SELECT * FROM `dict_plugin_Test` WHERE `plugin_name` = ?") var args string = "55 union select * from `dict_plugin_Test`" results, err := stmt.Query(args) if err != nil { fmt.Printf("query fail: %v", err) return err } defer stmt.Close() for results.Next() { err = results.Scan(.....) ...... }btw, C# 其实也支持预编译语句版本的sqlCommand:SqlCommand.Prepare()