目录
2.2 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预编译(?占位符)
2.3 然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换
2.4 MySQL服务端执行完整的SQL语句并将结果返回给客户端
由于笔者个人水平有限,行文如有不当,还请各位师傅评论指正,非常感谢
https://dev.mysql.com/doc/refman/5.7/en/sql-prepared-statements.htmlhttps://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat _Sheet.htm

用户输入的数据作为代码执行了
- 用户能控制传参
- 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'")

- 客户端对SQL语句进行占位符替换得到完整的SQL语句
- 客户端发送完整SQL语句到MySQL服务端
- MySQL服务端执行完整的SQL语句并将结果返回给客户端
总结:
一次编译,单次运行,此类普通语句被称作 Immediate Statements (即时 SQL)



处理后的数据就成这样:
- # 定义预处理语句 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'#的参数,所以返回的是空。
- vim /etc/mysql/mysql.conf.d/mysqld.cnf
- general_log=on
- general_log_file=/tmp/mysql.log
- # 查看log tail -f /tmp/mysql.log
- 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注入