golang mysql 防注入_Go,Gorm 和 Mysql 是如何防止 SQL 注入的

Go,Gorm 和 Mysql 是如何防止 SQL 注入的

SQL 注入和 SQL 預編譯技術

什么是 SQL 注入

所謂SQL注入(sql inject),就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來說,它是利用現有應用程序,將(惡意的)SQL命令注入到后臺數據庫引擎執行的能力,它可以通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。

SQL 注入例子

如下所示,是一個用戶進行登錄時,輸入用戶名和密碼,再將數據通過表單傳送到后端進行查詢的 SQL 語句。

sql = "SELECT USERNAME,PASSWORD FROM USER WHERE USERNAME='" + username + "' AND PASSWORD='" + password + "'";

上面這個 SQL 語句就存在 SQL 注入的安全漏洞。

假如 user 表中有用戶名為 123456 ,密碼為 123456 的記錄,而在前臺頁面提交表單的時候用戶輸入的用戶名和密碼是隨便輸入的,這樣當然是不能登錄成功的。

但是如果后臺處理的 SQL 語句是如上所寫,前臺頁面用戶名也是隨便輸入,而用戶輸入的密碼是這樣的 aaa' or '1'='1 ,處理登錄的 SQL 語句就相當于是這樣的:

SELECT USERNAME,PASSWORD FROM USER WHERE USERNAME='123456' AND PASSWORD='aaa' or '1'='1';

我們知道,1=1 是 true,所以上面這個 SQL 語句是可以執行成功的,這是一個 SQL 注入問題。

SQL 注入的解決

上述 SQL 注入問題產生的原因就是用戶的輸入是包含 SQL 語句的,而且后端執行 SQL 語句時直接將用戶的輸入和查詢的 SQL 語句進行了拼接。

因此,簡單的拼接用戶輸入的數據和后端的查詢 SQL 語句,是不可行的,我們需要將用戶的輸入作為一個完整的字符串,而忽略內部的 SQL 語句。當用戶輸入的密碼是這樣的 aaa’ or ‘1’='1 ,處理登錄的 SQL 語句實際應該執行的是:

SELECT USERNAME,PASSWORD FROM USER WHERE USERNAME='123456' AND PASSWORD="aaa' or '1'='1";

這樣就可以避免 SQL 注入導致的安全漏洞。

SQL 預編譯技術

解決 SQL 注入問題的這個方案的關鍵要點實際上是將 SQL 語句和用戶輸入的查詢數據分別進行處理,而不是一視同仁的作為 SQL 語句的不同部分進行拼接處理。在這個基礎上,就產生了 SQL 預編譯技術。

通常我們的一條 SQL 在 DB 接收到最終執行完畢返回可以分為下面三個過程:

詞法和語義解析

優化 SQL 語句,制定執行計劃

執行并返回結果

但是我們可以將其中需要用戶輸入的值用占位符替代,可以視為將 SQL 語句模板化或者說參數化,再將這樣的 SQL 語句進行預編譯的處理,在實際運行的時候,再傳入用戶輸入的數據。

使用這樣的 SQL 預編譯技術,除了可以防止 SQL 注入外,還可以對預編譯的 SQL 語句進行緩存,之后的運行就省去了解析優化 SQL 語句的過程,可以加速 SQL 的查詢。

Gorm 和 Go 端的 SQL 預編譯

在 Gorm 中,就為我們封裝了 SQL 預編譯技術,可以供我們使用。

db = db.Where("merchant_id = ?", merchantId)

在執行這樣的語句的時候實際上我們就用到了 SQL 預編譯技術,其中預編譯的 SQL 語句merchant_id = ?和 SQL 查詢的數據merchantId將被分開傳輸至 DB 后端進行處理。

db = db.Where(fmt.Sprintf("merchant_id = %s", merchantId))

而當你使用這種寫法時,即表示 SQL 由用戶來進行拼裝,而不使用預編譯技術,隨之可能帶來的,就是 SQL 注入的風險。

Gorm 端的 SQL 預編譯

// SQLCommon is the minimal database connection functionality gorm requires. Implemented by *sql.DB.

type SQLCommon interface {

Exec(query string, args ...interface{}) (sql.Result, error)

......

}

Go 端的 SQL 預編譯

// src/database/sql/sql.go

func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), query string, args []interface{}) (res Result, err error) {

......

resi, err = ctxDriverExec(ctx, execerCtx, execer, query, nvdargs)

......

if err != driver.ErrSkip {

......

return driverResult{dc, resi}, nil

}

......

si, err = ctxDriverPrepare(ctx, dc.ci, query)

......

ds := &driverStmt{Locker: dc, si: si}

......

return resultFromStatement(ctx, dc.ci, ds, args...)

}

實際的實現最終還是落到了go-sql-driver上,如下面代碼所示go-sql-driver支持開啟預編譯和關閉預編譯,由mc.cfg.InterpolateParams = false、true決定,可以看出gorm中mc.cfg.InterpolateParams = true,即開啟了預編譯

func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {

......

if len(args) != 0 {

if !mc.cfg.InterpolateParams {

return nil, driver.ErrSkip

}

prepared, err := mc.interpolateParams(query, args)

if err != nil {

return nil, err

}

query = prepared

}

......

err := mc.exec(query)

......

return nil, mc.markBadConn(err)

}

Mysql 端的SQL 預編譯

在MySQL中是如何實現預編譯的,MySQL在4.1后支持了預編譯,其中涉及預編譯的指令實例如下

可以通過PREPARE預編譯指令,SET傳入數據,通過EXECUTE執行命令

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';

Query OK, 0 rows affected (0.00 sec)

Statement prepared

mysql> SET @a = 3;

Query OK, 0 rows affected (0.00 sec)

mysql> SET @b = 4;

Query OK, 0 rows affected (0.00 sec)

mysql> EXECUTE stmt1 USING @a, @b;

+------------+

| hypotenuse |

+------------+

| 5 |

+------------+

1 row in set (0.00 sec)

mysql> DEALLOCATE PREPARE stmt1;

Query OK, 0 rows affected (0.00 sec)

首先我們先簡單回顧下客戶端使用 Prepare 請求過程:

客戶端發起 Prepare 命令將帶 “?” 參數占位符的 SQL 語句發送到數據庫,成功后返回 stmtID。

具體執行 SQL 時,客戶端使用之前返回的 stmtID,并帶上請求參數發起 Execute 命令來執行 SQL。

不再需要 Prepare 的語句時,關閉 stmtID 對應的 Prepare 語句。

這里展示不使用 sql 預編譯和使用 sql 預編譯時的 Mysql 的日志。

2020-06-30T08:14:02.430089Z 10 Query COMMIT

2020-06-30T08:14:02.432995Z 10 Query select * from user where merchant_id='123456'

2020-06-30T08:15:10.581287Z 12 Query COMMIT

2020-06-30T08:15:10.584109Z 12 Prepare select * from user where merchant_id =?

2020-06-30T08:15:10.584725Z 12 Execute select * from user where merchant_id ='123456'

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281958.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281958.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281958.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

wav2midi 音樂旋律提取算法 附可執行demo

前面提及過,音頻指紋算法的思路。 也梳理開源了兩個比較經典的算法。 https://github.com/cpuimage/shazam https://github.com/cpuimage/AudioFingerprinter 后來一段時間,稍微看了下這兩個算法,還有不少可以精簡優化的空間。 例如抗噪&…

全新升級的AOP框架Dora.Interception[5]: 實現任意的攔截器注冊方式

Dora.Interception提供了兩種攔截器注冊方式,一種是利用標注在目標類型、屬性和方法上的InterceptorAttribute特性,另一種采用基于目標方法或者屬性的調用表達式。通過提供的擴展點,我們可以任何我們希望的攔截器注冊方式。目錄一、IIntercep…

SCAU 算法課的題

8594 有重復元素的排列問題(優先做) 時間限制:1000MS 內存限制:1000K提交次數:1610 通過次數:656 題型: 編程題 語言: G;GCC;VC Description 設集合R{r1,r2,...,rn}是要進行排列的n個元素,其中r1,r2,...,rn可能相同。 試著設計一個算法&am…

react 數組新增_React 新特性 Hooks 講解及實例(二)

本文是 React 新特性系列的第二篇,第一篇請點擊這里:React 新特性講解及實例什么是 HooksHook 是 React 16.8 的新增特性。它可以讓你在不編寫 類組件 的情況下使用 state以及其他的 React 特性。類組件的不足狀態邏輯復用難缺少復用機制渲染屬性和高階組…

智課雅思詞匯---二十二、-al即是名詞性后綴又是形容詞后綴

智課雅思詞匯---二十二、-al即是名詞性后綴又是形容詞后綴 一、總結 一句話總結: 后綴:-al ②[名詞后綴] 1、構成抽象名詞,表示行為、狀況、事情 refusal 拒絕 proposal 提議 withdrawal 撤退 1、名詞性后綴acy是什么意思? 后綴&a…

javascript事件處理程序

javascript 事件處理程序 1、普通事件處理程序 <input type"button" value"click me" οnclick"showMessage()" /> function showMessage(){alert("clicked");} 2、DOMO 級事件處理程序 <span style"white-space:pre&…

eclipse新發現功能之dos和terminal(ssh連接)

dos功能&#xff1a; window——》show view——》other——》remote systems&#xff0c;選擇remote shell&#xff0c;選擇確定或者雙擊&#xff0c;打開了一個新工具窗口。點擊remote shell窗口最右上角的小三角&#xff0c;在launch子菜單中選擇local&#xff0c;點擊即可。…

7天學會python_7天學會Python最佳可視化工具Seaborn(五):結構化展示多維數據

當探索具有中等數量(不多不少的意思……)維度的數據集時&#xff0c;一個很好的方式是基于不同的子數據集構建不同的實例&#xff0c;并將它們以網格的方式組織在一張圖之中。這種技術有時被稱為“lattice”或“trellis”(大概是格子圖、網格圖)&#xff0c;這跟“small multip…

面對峰值響應沖擊,解決高并發的三大策略

2019獨角獸企業重金招聘Python工程師標準>>> 當前在互聯網的大潮下&#xff0c;眾所周知淘寶、京東這些交易系統每天產生的數據量都是海量的&#xff0c;每天的交易并發也是驚人的&#xff0c;尤其是“雙11”、“6.18”這些活動&#xff0c;對系統的峰值響應提出了非…

.NET 采用 SkiaSharp 生成二維碼和圖形驗證碼及圖片進行指定區域截取方法實現

在最新版的 .NET 平臺中&#xff0c;微軟在逐步放棄 System.Drawing.Imaging &#xff0c;給出的理由如下&#xff1a;System.Drawing命名空間對某些操作系統和應用程序類型有一些限制。在Windows&#xff0c; System.Drawing 依賴于GDI操作系統附帶的本機庫。 某些Windows SKU…

Linux運維人員必會開源運維工具體系

新手必會用深&#xff08;8-15k&#xff09;標記&#xff0c;老鳥必會深淺藍色(15-25K)標記操作系統&#xff1a;Centos,Ubuntu,Redhat,suse,Freebsd網站服務&#xff1a;nginx,apache,lighttpd,php,tomcat,resin數據 庫&#xff1a;MySQL,MariaDB,PostgreSQLDB中間件&#x…

unity讀取Text

sing UnityEngine;using System.Collections;using System.IO; //需要導入System.IO&#xff0c;主要使用它的File類public class TextTest : MonoBehaviour { private string Mytxt; //用來存放文本內容 void Start() { Mytxt ReadFile("C:\\Users\\Admin\\Desktop\\測試…

hibernate mysql 主從_MYSQL主從復制和寫分離

基礎篇https://edu.51cto.com/course/19845.htmlhttps://edu.51cto.com/course/19845.htmlhttps://edu.51cto.com/course/19841.htmlhttps://edu.51cto.com/course/21197.htmlhttps://edu.51cto.com/course/19886.htmlhttps://edu.51cto.com/course/19887.htmlhttps://edu.51ct…

深入剖析Redis系列(五) - Redis數據結構之字符串

前言 字符串類型 是 Redis 最基礎的數據結構。字符串類型 的值實際可以是 字符串&#xff08;簡單 和 復雜 的字符串&#xff0c;例如 JSON、XML&#xff09;、數字&#xff08;整數、浮點數&#xff09;&#xff0c;甚至是 二進制&#xff08;圖片、音頻、視頻&#xff09;&am…

全新升級的AOP框架Dora.Interception[6]: 框架設計和實現原理

本系列前面的五篇文章主要介紹Dora.Interception的編程模式以及對它的擴展定制&#xff0c;現在我們來聊聊它的設計和實現原理。目錄一、調用鏈抽象二、基于約定的攔截器定義三、基于調用上下文的依賴注入容器四、攔截器的提供五、調用鏈的構建六、方法攔截的實現原理七、依賴注…

activemq 安全連接

一、定義用戶組1.1 simpleAuthenticationPlugin通過在activemq.xml中配置用戶組<plugins> <simpleAuthenticationPlugin> <users> <authenticationUser username"admin" password"password" groups"admins,publishers,consumer…

React Native在Android當中實踐(五)——常見問題

React Native在Android當中實踐&#xff08;一&#xff09;——背景介紹 React Native在Android當中實踐&#xff08;二&#xff09;——搭建開發環境 React Native在Android當中實踐&#xff08;三&#xff09;——集成到Android項目當中 React Native在Android當中實踐&#…

完成登錄與注冊頁面的前端

完成登錄與注冊頁面的HTMLCSSJS&#xff0c;其中的輸入項檢查包括&#xff1a; 用戶名6-12位 首字母不能是數字 只能包含字母和數字 密碼6-12位 注冊頁兩次密碼是否一致 JS&#xff1a; function fnLogin() {var uSer document.getElementById("user");var pAss do…

mysql505復位密碼_mysql5 如何復位根用戶密碼[官方文檔]

如何復位根用戶密碼如果你從未為MySQL設置根用戶密碼&#xff0c;服務器在以根用戶身份進行連接時不需要密碼。但是&#xff0c;建議你為每個賬戶設置密碼如果你以前設置了根用戶密碼&#xff0c;但卻忘記了該密碼&#xff0c;可設置新的密碼。下述步驟是針對Windows平臺的。在…

WPF效果第二百零一篇之實現合并單元格

早一段時間又一次出差青海省西寧市;回來又是總結又是各種瑣事,也沒顧得上去分享點東西;大周末的就在家分享一下,這二天再次基于ListBox實現的合并單元格的效果:1、ListBox嵌套ListBox的前臺布局:<ListBox ItemsSource"{Binding LCPListData}" x:Name"Manufac…