SQL Injection 防御——预编译

目录

(一)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 注入发生的原因

形成原因:

 用户输入的数据作为代码执行了

  1. 用户能控制传参
  2. SQL语句中拼接了用户传参的内容
  3. 拼接后的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语句执行过程


  1. 客户端对SQL语句进行占位符替换得到完整的SQL语句
  2. 客户端发送完整SQL语句到MySQL服务端
  3. 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", 
   }) 
}
预处理有什么好处:
  1. 优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本
  2. 避免SQL注入
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Camelus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值