Dapper防sql注入,同一条SQL支持多种数据库
前言
防SQL注入,常用的方案是使用Dapper執行SQL的參數化查詢。例如:
using?(IDbConnection?conn?=?CreateConnection()) {string?sqlCommandText?=?@"SELECT?*?FROM?USERS?WHERE?ID=@ID";Users?user?=?conn.Query<Users>(sqlCommandText,?new?{?ID?=?2?}).FirstOrDefault();Console.WriteLine(user.Name); }但是,不同數據庫支持不同的sql參數格式,例如,ORACLE必須使用:ID,否則上述代碼會報錯:
Pseudo-Positional Parameters
查看Dapper的源代碼[1],發現有這樣一段:
cmd.CommandText?=?pseudoPositional.Replace(cmd.CommandText,?match?=> {string?key?=?match.Groups[1].Value;if?(!consumed.Add(key)){throw?new?InvalidOperationException("When?passing?parameters?by?position,?each?parameter?can?only?be?referenced?once");}else?if?(parameters.TryGetValue(key,?out?IDbDataParameter?param)){if?(firstMatch){firstMatch?=?false;cmd.Parameters.Clear();?//?only?clear?if?we?are?pretty?positive?that?we've?found?this?pattern?successfully}//?if?found,?return?the?anonymous?token?"?"if?(Settings.UseIncrementalPseudoPositionalParameterNames){param.ParameterName?=?(++index).ToString();}cmd.Parameters.Add(param);parameters.Remove(key);consumed.Add(key);return?"?";}else{//?otherwise,?leave?alone?for?simple?debuggingreturn?match.Value;} });通過查看Dapper教程[2],原來,這是實現被稱為Pseudo-Positional Parameters(偽位置參數)的代碼,作用是為了不支持命名參數的數據庫提供者能夠使用參數化SQL,例如OleDB:
//代碼 var?docs?=?conn.Query<Document>(@"select?*?from?Documentswhere?Region?=??region?and?OwnerId?in??users?",?new?{?region,?users?}).AsList();//SQL select?*?from?Documentswhere?Region?=??and?OwnerId?in?(?,?,?)自定義Pseudo-Positional Parameters
依葫蘆畫瓢,我們可以實現自己的Pseudo-Positional Parameters,以便支持更多的數據提供者:
private?static?readonly?Regex?pseudoRegex?=?new?Regex(@"\$([\p{L}_][\p{L}\p{N}_]*)\$",?RegexOptions.IgnoreCase?|?RegexOptions.CultureInvariant?|?RegexOptions.Compiled);public?static?string?ReplacePseudoParameter(IDbConnection?conn,?string?cmdText) {return?pseudoRegex.Replace(cmdText,?match?=>?{var?key?=?match.Groups[1].Value;if?(conn?is?OleDbConnection){return?"?"?+?key?+?"?";}return?(conn?is?OracleConnection???":"?:?"@")?+?key;}); }使用方式是在參數名稱兩邊加上$:
string?sqlCommandText?=?@"SELECT?*?FROM?USERS?WHERE?ID=$ID$";Users?user?=?conn.Query<Users>(ReplacePseudoParameter(conn,?sqlCommandText),?new?{?ID?=?2?}).FirstOrDefault();結論
通過實現Pseudo-Positional Parameters功能,我們讓Dapper防sql注入支持了多種數據庫。
如果你覺得這篇文章對你有所啟發,請關注我的個人公眾號”My IO“
參考資料
[1]
源代碼: https://github.com/DapperLib/Dapper/blob/main/Dapper/SqlMapper.cs#L1783
[2]Dapper教程: https://riptutorial.com/Dapper/example/13835/pseudo-positional-parameters--for-providers-that-don-t-support-named-parameters-
總結
以上是生活随笔為你收集整理的Dapper防sql注入,同一条SQL支持多种数据库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Dapr牵手.NET学习笔记:绑定
- 下一篇: 01Prism WPF 入门实战 - 项