• 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语句必须能在数据库中执行
    1. def bypass_from_param(string):
    2. sql_string = "select * from products where category = '{}' and released = 0".format(string) print(sql_string)
    3. if __name__ == '__main__':
    4. 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、代码实现


    1. # 定义预处理语句 PREPARE stmt_name FROM preparable_stmt;
    2. # 执行预处理语句 EXECUTE stmt_name [USING @var_name [, @var_name] ...];
    3. # 删除(释放)定义 {DEALLOCATE | DROP} PREPARE stmt_name;
    4. # 验证 use sql_inject;
    5. prepare select_content from 'select id,name,content,
    6. released from products where category = ? and released = ?';
    7. set @a='Gifts'
    8. set @b=0
    9. execute select_content using @a,@b;

            假如我们a输入的是Gifts'#,输出的数据是空,原因很简单SQL语句之前已经编译过了,现在传入的是参数,表里没有Gift'#的参数,所以返回的是空。

    1、数据库开启Log

    1. vim /etc/mysql/mysql.conf.d/mysqld.cnf
    2. general_log=on
    3. general_log_file=/tmp/mysql.log
    4. # 查看log tail -f /tmp/mysql.log

    2、服务端代码

    1. package api
    2. import (
    3. "log"
    4. "net/http"
    5. "sql_injection/model"
    6. "github.com/gin-gonic/gin"
    7. )
    8. func ProductsHandler(c *gin.Context) {
    9. a := c.Query("category")
    10. s := c.Query("released")
    11. log.Println(a)
    12. //sqlStr := fmt.Sprintf(`select id,name,content,released from products where category = '%s' and released = %s`, a, s)
    13. // 预编译模板
    14. sqlStr := "select id,name,content,released from products where category = ? and released = ? "
    15. log.Println(sqlStr)
    16. stmt, err2 := model.DB.Prepare(sqlStr)
    17. if err2 != nil {
    18. c.JSON(http.StatusOK, gin.H{
    19. "code": 404, "err":
    20. err2.Error(),
    21. "msg": "error",
    22. })
    23. return
    24. }
    25. rows, err := stmt.Query(a, s)
    26. if err != nil {
    27. c.JSON(http.StatusOK,
    28. gin.H{
    29. "code": 404,
    30. "err": err.Error(),
    31. "msg": "error", })
    32. return }
    33. var r []model.Product
    34. for rows.Next() {
    35. var p model.Product
    36. if rowErr := rows.Scan(&p.Id, &p.Name, &p.Content, &p.Released); rowErr != nil
    37. {
    38. c.JSON(200, gin.H{
    39. "code": 404,
    40. "err": rowErr.Error(),
    41. "msg": "error",
    42. })
    43. }r = append(r, p)
    44. }
    45. c.JSON(
    46. 200, gin.H{
    47. "code": 0,
    48. "data": r,
    49. "msg": "success",
    50. })
    51. }
    预处理有什么好处:
    1. 优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本
    2. 避免SQL注入
  • 相关阅读:
    【Educoder作业】C&C++函数实训
    技术分享| 快对讲视频调度功能说明
    Datakit,真正的统一可观测性 Agent
    【web-渗透测试方法】(15.5)测试访问控件
    [WACON CTF 2023] WhiteArts
    Python——缩进和选择
    【LeetCode】235.二叉搜索树的最近公共祖先
    Linux系统调优详解(十二)——网卡绑定技术
    bp神经网络图像特征提取,神经网络如何提取特征
    RestTemplate上传、下载文件
  • 原文地址:https://blog.csdn.net/m0_61506558/article/details/126913694