目录
(一)Reference:
形成原因:
(二)什么是预处理
1、普通的SQL语句执行过程
2、预处理执行过程
2.1 把SQL语句分成两部分,命令部分和数据部分
2.2 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预编译(?占位符)
?2.3?然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换
?2.4??MySQL服务端执行完整的SQL语句并将结果返回给客户端
总结:
?3、代码实现
1、数据库开启Log
2、服务端代码
?????????由于笔者个人水平有限,行文如有不当,还请各位师傅评论指正,非常感谢
(一)Reference:
https://dev.mysql.com/doc/refman/5.7/en/sql-prepared-statements.html
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat
_Sheet.htm
????????本篇文章主要介绍预编译,首先
回顾
SQL
注入发生的原因
形成原因:
?用户输入的数据作为代码执行了
- 用户能控制传参
- SQL语句中拼接了用户传参的内容
- 拼接后的SQL语句必须能在数据库中执行
def bypass_from_param(string):
sql_string = "select * from products where category = '{}' and released = 0".format(string) print(sql_string)
if __name__ == '__main__':
bypass_from_param("Gifts'")
(二)什么是预处理
1、普通的SQL语句执行过程
- 客户端对SQL语句进行占位符替换得到完整的SQL语句
- 客户端发送完整SQL语句到MySQL服务端
- MySQL服务端执行完整的SQL语句并将结果返回给客户端
总结:
????????
一次编译,单次运行,此类普通语句被称作 Immediate Statements (即时 SQL)
2、预处理执行过程
2.1 把SQL语句分成两部分,命令部分和数据部分
2.2 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预编译(?占位符)
?2.3?然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换
?2.4??MySQL服务端执行完整的SQL语句并将结果返回给客户端
????????处理后的数据就成这样:
总结:
????????
所谓预编译语句就是将此类 SQL 语句中的值用占位符替代,可以视为将 SQL 语句模板化或者说参数化,一般称这类语句叫Prepared Statements
?3、代码实现
# 定义预处理语句 PREPARE stmt_name FROM preparable_stmt;
# 执行预处理语句 EXECUTE stmt_name [USING @var_name [, @var_name] ...];
# 删除(释放)定义 {DEALLOCATE | DROP} PREPARE stmt_name;
# 验证 use sql_inject;
prepare select_content from 'select id,name,content,
released from products where category = ? and released = ?';
set @a='Gifts'
set @b=0
execute select_content using @a,@b;
????????假如我们a输入的是Gifts'#,输出的数据是空,原因很简单SQL语句之前已经编译过了,现在传入的是参数,表里没有Gift'#的参数,所以返回的是空。
1、数据库开启Log
vim /etc/mysql/mysql.conf.d/mysqld.cnf
general_log=on
general_log_file=/tmp/mysql.log
# 查看log tail -f /tmp/mysql.log
2、服务端代码
package api
import (
"log"
"net/http"
"sql_injection/model"
"github.com/gin-gonic/gin"
)
func ProductsHandler(c *gin.Context) {
a := c.Query("category")
s := c.Query("released")
log.Println(a)
//sqlStr := fmt.Sprintf(`select id,name,content,released from products where category = '%s' and released = %s`, a, s)
// 预编译模板
sqlStr := "select id,name,content,released from products where category = ? and released = ? "
log.Println(sqlStr)
stmt, err2 := model.DB.Prepare(sqlStr)
if err2 != nil {
c.JSON(http.StatusOK, gin.H{
"code": 404, "err":
err2.Error(),
"msg": "error",
})
return
}
rows, err := stmt.Query(a, s)
if err != nil {
c.JSON(http.StatusOK,
gin.H{
"code": 404,
"err": err.Error(),
"msg": "error", })
return }
var r []model.Product
for rows.Next() {
var p model.Product
if rowErr := rows.Scan(&p.Id, &p.Name, &p.Content, &p.Released); rowErr != nil
{
c.JSON(200, gin.H{
"code": 404,
"err": rowErr.Error(),
"msg": "error",
})
}r = append(r, p)
}
c.JSON(
200, gin.H{
"code": 0,
"data": r,
"msg": "success",
})
}
预处理有什么好处:
- 优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本
- 避免SQL注入
|