sticky
[分享] 何謂 SQL injection,在此整理分享 RRS feed

  • 一般討論

  • 最近常常可以在很多的討論串中看到有些人在問問題時,
    裡面的SQL 語法是用 + 呀 & 呀等等,用串的串起來,
    這時候就會發現該篇回應裡會提到這樣寫SQL語法有很大的問題,會造成SQL injection的危險性,建議請改成參數化來使用,

    但可能有些是新手程式設計人員,並不了解甚麼是SQL injection,
    或者想說我的問題解決了就好,幹嘛要參數化呀...

    這問題其實發生很久了,每隔一段時間就會發現有這樣的發問者出現,
    正好最近Youtube有一個影片,或許可以先打開看一看,可以先了解SQL injection的危險性到底多危險

    [補充 :  這個影片的作者是國外的一個MVP所錄製拍攝的,他的Blog可參考
    http://www.troyhunt.com/2012/10/hacking-is-childs-play-sql-injection.html ]

    https://www.youtube.com/watch?v=Fp47G4MQFvA (如果有違反甚麼規定,請告知一聲,將會自己移除)
    因此順便整理一下以前看過的幾篇好文連結,詳細的說明可以看下面連結裡的文章,來更深刻的了解。

    其實這個問題已經存在很久了,

    當使用串字串的方法來組合你的SQL時,往往會成為一些有心人是利用T-SQL來填空,
    導致利用一些指令來刪除或撈取你的資料庫資料,

    因此很多的回應者都會建議這些發問者,不要再用 + 呀 & 呀去組合,

    要避免的方法有很多,例如參數化、利用Asp.net的控制項、利用Stored procedures、利用ORM的架構操控資料庫.....等等

    微軟官方網站也有兩篇好文,也可以參考參考

    SQL Injection (資料隱碼)– 駭客的 SQL填空遊戲(上)
    http://www.microsoft.com/taiwan/sql/sql_injection_g1.htm

    SQL Injection (資料隱碼)– 駭客的 SQL填空遊戲(下)
    http://www.microsoft.com/taiwan/sql/SQL_Injection_G2.htm

    此外有些部落客在過去也都寫過很多好文,也可以參考參考

    像是黑暗大寫過的
    游擊式的SQL Injection攻擊
    blog.darkthread.net/post-2008-05-22-hit-and-run-sql-injection-attack.aspx

    或是91大寫過的 

    [Security]SQL injection的簡介與預防
    www.dotblogs.com.tw/hatelove/archive/2011/12/19/what-is-sql-injection-and-how-to-prevent.aspx

    如果還有甚麼好文章,或是甚麼建議,希望也可以在此一起討論。


    • 已編輯 Bruce_柏 2012年10月18日 上午 10:21
    2012年10月18日 上午 06:28

所有回覆

  • 置頂的wiki文,最下面的「安全相關設計」就有許多SQL injection相關的文章。(不只是SQL injection,還有一些其他基本要了解的觀念,那都是因為工程師偷懶、不專業、沒盡到本分所造成的問題)

    ex:

    安全相關設計

    我的作法就是,上來發問的朋友,如果程式碼中帶著SQL injection的漏洞,fix漏洞之前,不協助他解決原本的問題。因為基本上碰到再大的問題,都沒這問題大。


    授人以魚,三餐之需;授人以漁,終生之用。
    希望各位發問的朋友,得到的是如何釣魚的知識。之後也可以分享給別人,釣魚的知識。而不是肚子餓了,就上來討魚吃。

    若您的程式碼有SQL injection的問題,在修改完畢之前,我不願意給您任何解答。因為解決了您的程式問題,造成更大的系統漏洞問題,還不如讓程式壞掉。

    請參考:SQL injection簡介與解決方式

    常用資源參考:


    小弟的blog: In 91,wiki: my wiki

    2012年10月18日 上午 06:51
    版主
  • 本文無限期置頂。

    學習不是查個 Google 套個書上的範例就算了,而是去熟悉了解每個程式碼背後的意義,否則就算學個幾百年,它也不會是你的。

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2012年10月18日 上午 07:00
    版主
  • [Share]

    SQL Injection 攻擊實例與防範之道
    http://renjin.blogspot.tw/2008/05/sql-injection-attacks-by-example.html

    2012年11月9日 上午 01:45
  • 若使用 Microsoft 最新的 Entityframewok 技術

    SQL injection 不必再擔心

    2013年5月5日 上午 04:08
  • 其實這是根本的問題
    常碰到這樣寫法是
    1.老師這樣教
    2.書上這樣寫
    3.前輩這樣寫
    再加上自己沒有去注意安全性的問題
    噵致 SQL Injection 這個已經蠻久的問題一直沒法根治

    最近還有碰到的情況是
    客戶端使用 Server 2008 + SQL2000
    只要用 parameter 帶參數會一直出現錯誤
    反而用 & 去串就沒事
    這....真的無言啊!!!!!

    2013年11月4日 上午 01:40
  • Y.T.Lin

    請不要再使用串字串方式,

    針對客戶端問題,可以至其他分區提供錯訊息與資訊,我相信大家很願意幫忙你找出問題點。


    理直氣和,切記。

    Blog: http://blog.kkbruce.net

    Book:《ASP.NET MVC 4 網站開發美學

    2013年11月4日 上午 01:58
  • 1.老師這樣教 ( ... )
    2.書上這樣寫 (可以列舉出是哪些書...)
    3.前輩這樣寫 (可以說說是誰...)

    SQL Server 2000 一樣可以用 parameter。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2013年11月4日 上午 02:25
    版主
  • 大大~~誤會啊!!!
    我現在都是用 parameter(SQL Server 2008)
    只是碰上了 SQL Server 2000
    用 parameter 就不能 work 了

    2013年11月4日 上午 05:44
  • 您好:

    剛剛找到一台機器幫您測試過(現在 Windows 7要裝SQL 2000還真麻煩,找不到SQL 2000光碟了)

    Windows 2003 R2 + .NET 3.5 + SQL 2000

    我使用 SqlCommand的 .Parameters.AddWithValue("@參數", Request("變數"))

    可以正常運作喔。

         

    另外,我出書也當老師

    一開始教ADO.NET 的時候,因為程式碼長,會嚇到初學者

    我的確沒教 Parameter的寫法,但我提供的 "範例"則是兩者都有(字串相連、參數寫法)

       

    後續教到會員登入(帳號、密碼)與後端管理區

    則會示範SQL Injection如何攻擊?如何防禦?這時候就會強調 Parameter的重要。

    不同階段,用不同的方法教學與分享,以求得最佳的學習效果。

       

    問題拉回來,上課的學生、讀者會這麼認真嗎?

    會把書看完?會追根究柢嗎?

    不會!.....他們隨手找到範例就抄了,管他去死?

    我還看見有人問我 SqlDaraReader的 .ExecuteReader()方法搭配 Insert into為何會出錯?

    因為他從網站上找到一段ADO.NET範例就抄了、就上了,管他去死?

     .ExecuteReader()方法? .ExecuteNonQuery()方法?差異在哪?完全不管。

       

    反正都是別人的錯,是老師爛?書本爛?網路上分享範例的人有錯?

    自己不求甚解、自己看書看一半、自己只抄襲不求理解、自己拒絕學習、自己Bumbler & Bungling.....都沒錯

           

    當然,這種四處乞討程式碼、四處兜(湊)程式碼的,我也....管他去X

    推薦這篇文章----

    Bill叔的經典好文 -- 讀書與上課
    http://www.dotblogs.com.tw/billchung/archive/2010/11/28/19767.aspx

    或許是網際網路太發達且資訊已經多到爆炸,
    也許有人覺得要對一門電腦技術
    精通 只要上網查查資料、看看別人的部落格就有機會達成這樣的目標。

    我不否認應該有少數這樣具有特別天份的人,這類的人多半對於知識的組織與吸收是有獨到之處,
    不過這也意味著 
    大部份的人 走這條路通常都會進到死胡同
    很快地將會遭遇許多技術瓶頸的挑戰。
    ....詳見全文



    我的書 與 ASP.NET教學網站 http://www.dotblogs.com.tw/mis2000lab/


    2013年11月12日 上午 03:29
  • 感謝 MIS2000 大大提供的程式片段
    請問這是 ado.net(SqlDataAdapter)的方式嗎?
    傳回的型態為 ?
    可以用 ctype 強制轉型呢?

    因為小弟是從圖形介面進入.net的
    所以後續改程式都沿用原有的結構
    現在寫的方式如下(select)
    連到 sql server 2012

    ' sql server 2012       
    Dim DbLink As New SqlDataSource     
    Dim GetDataView As Data.DataView
         
     With DbLink
      .ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("DataBaseLink2012").ConnectionString
      .SelectCommand = " select * from employee "
      .SelectCommand += " where employee_dept =@DeptNo "
      .SelectParameters.Add("DeptNo",dept.text.toString())
        .DataBind()
        GetDataView = CType(.Select(DataSourceSelectArguments.Empty), Data.DataView)
        .Dispose()
      End With
     
    之後的程式對 dataview 做處理,這是正常運作的
    同樣的程式連到 sql server 2000 

    ' sql server 2000       
    Dim DbLink As New SqlDataSource     
    Dim GetDataView As Data.DataView
         
     With DbLink
      .ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("DataBaseLink2000").ConnectionString
      .ProviderName = "System.Data.OleDb"
      .SelectCommand = " select * from employee "
      .SelectCommand += " where employee_dept =@DeptNo "
      .SelectParameters.Add("DeptNo",dept.text.toString())
        .DataBind()
        GetDataView = CType(.Select(DataSourceSelectArguments.Empty), Data.DataView)
        .Dispose()
      End With 

    程式錯誤!!

    看來只好全面改寫了~~~


    • 已編輯 Y.T.Lin 2014年1月2日 上午 02:41
    2014年1月2日 上午 02:40
  • 要進階的話 , 光用圖形化的方式 , 不容易達到 

    建議您得學會 ADO.NET (ADO.NET 概觀)


    軟體開發領域裡區區一個迷途工程師
    MyBook: HTML5 & JavaScript程式開發實戰 MyBlog: http://www.dotblogs.com.tw/ian/
    開發ASP.NET您要瞭解的基楚

    2014年1月2日 上午 04:03
    版主
  • 毛病出在 Provider Name 吧, OleDb 和 SqlClient 使用參數的方法不一樣.

    要了解 ADO.NET , 請把 No.18 給的參考看完, 那裡面有一大串連結, 是非常完整的學習文章

    至於參數, 就是其中一個章節

    http://msdn.microsoft.com/zh-tw/library/yy6y35y8(v=vs.110).aspx


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2014年1月2日 下午 05:00
  • ADO.NET的參數寫法(DataReader / DataSet)

    http://www.dotblogs.com.tw/mis2000lab/archive/2014/08/29/ado.net_parameter_sql_injection_20140829.aspx

    希望對您有幫助。

    ....................................................................................................................................................

    DataReader (SqlCommand)

                String SQLString = "Select * From test Where id = @id ";    // 注意到沒?連「單引號」都不可以出現
     
                SqlCommand cmd = new SqlCommand(SQLString, Conn);
     
                cmd.Parameters.Add("@id", SqlDbType.Int, 4);
                cmd.Parameters["@id"].Value =TextBox1.Text;
     
                //簡易寫法。 cmd.Parameters.AddWithValue("@參數名稱", 輸入的數值);
                //上面兩段參數,可以寫成  cmd.Parameters.AddWithValue("@id", TextBox1.Text);

     

    ....................................................................................................................................................

    DataSet / DataTable (SqlDataAdapter)

    //注意!!資料隱碼攻擊(Sql Injection),請使用參數的寫法。
     
                String SQLString = "Select * From test Where id = @id ";  // 注意到沒?連「單引號」都不可以出現
     
                SqlDataAdapter myAdapter = new SqlDataAdapter(SQLString, Conn);
                //== 參數必須在執行SQL指令的時候,寫在下方等待呼叫。不然程式會出錯。
     
                    ////舊的寫法:
                    //myAdapter.SelectCommand.Parameters.Add("@id", SqlDbType.Int, 4);
                    //myAdapter.SelectCommand.Parameters["@id"].Value = TextBox1.Text;
                    
                    //新的寫法:合併在一起寫
                    myAdapter.SelectCommand.Parameters.AddWithValue("@id", TextBox1.Text);

     


    我的書 與 ASP.NET教學網站 http://www.dotblogs.com.tw/mis2000lab/

    2014年9月9日 上午 07:20
  • 話說,我曾見識過有人寫DB預存程序,雖然使用參數化寫法,還是有可能被SQL Injection XDD

    例如:

    --參數拼接字串的錯誤示範
    CREATE Procedure [dbo].[TestProcedure]
    (
     @Name nvarchar(6),
     @Seq bigint
    )
    As
    Begin
    
    Declare @sql varchar(4000)
    Set @sql='Select ID,Name,Seq
              From TestTable
              Where 1=1 '
    
    		 
    IF IsNull(@Name,'')<>''
    Begin
     set @sql = @sql +' And Name Like  ''%'+@Name+'%''  '
    
    End
    
    IF (@Seq Is Not Null)
    Begin
    
    set @sql = @sql +' And Seq < '+ Convert(varchar,@Seq)
    End 
    
    set @sql = @sql +' Order by Seq ASC'
    Exec(@sql)--執行SQL字串
    
    End
    
    
    GO
    

    想撰寫純T-SQL來實作查詢條件篩選(例如在預存程序裡),以下分享幾種正確無SQL Injection風險的範例

    Declare @ID bigint =NULL --給NULL或-1,相當於略過ID查詢條件
    Declare @Seq bigint =5 --給NULL或-1,相當於略過Seq查詢條件
    Declare @Name nvarchar(10) = '%Sha%' --'%%'萬用字元必須是參數值,而不要在SQL語句中拼接'%'萬用字元
    --@Name給NULL或空字串,相當於略過Name查詢條件
    
    --第一種,由於使用Or,查詢效能可能不大好
    Select ID,Name,Seq from TestTable
    Where ( Seq< @Seq Or  IsNULL(@Seq,-1)=-1)
          And   
    	  ( Name Like @Name Or IsNull(@Name,'')='')
    	  And 
    	  ( ID = @ID Or IsNull(@ID,-1)=-1)
    
    --第二種,和第三種概念類似
    SELECT  ID,Name,Seq 
    FROM TestTable
    WHERE seq < IIF(IsNull(@Seq,-1) <>-1,@Seq,100000)
    And Name Like IIF(isNUll(@Name,'') <>'',@Name,Name)
    And ID = IIF(isNUll(@ID,-1) <>-1,@ID,ID)
    
    --第三種
    SELECT  ID,Name,Seq 
    FROM TestTable
    Where Seq <  CASE WHEN IsNull(@Seq,-1) <>-1 THEN @Seq ELSE 100000 END --當Seq為-1或Null時就給100000,相當於撈全部資料
    AND	Name Like CASE WHEN isNUll(@Name,'') <>'' THEN @Name ELSE Name END --當@Name為Null或空字串時,Name=Name,相當於撈全部資料
    AND	ID = CASE WHEN isNUll(@ID,-1) <>-1 THEN @ID ELSE ID END --當@ID為Null或-1時,ID=ID,相當於撈全部資料
    
    
    
    
    
    
    /***※補充:SQL In查詢語句和時間區間的查詢範例***/
    
    Declare @Param nvarchar(4000)  = 'Shadow,Sharon'
    Declare @StartDate Datetime ='2015-12-01'
    Declare @EndDate Datetime='2015-12-09'
    --第一種寫法,我已經事先在資料表新增名為InsertDatetime時間欄位
    Select ID,Name,Seq 
    from TestTable
    where (IsNull(@Param,'')=''  Or  CharIndex(Name,@Param)>0)
    And ( (@StartDate Is NULL And @EndDate Is NULL) Or (InsertDatetime Between @StartDate And @EndDate))
    
    
    --第二種寫法
    Select ID,Name,Seq  
    from TestTable
    Where 
     @Param Like IIF(isNUll(@Param,'') <>'','%'+Name+'%',@Param)
     And 
    ( InsertDatetime>= IIF((@StartDate Is NULL And @EndDate Is NULL),InsertDatetime,@StartDate) 
      And InsertDatetime<=IIF((@StartDate Is NULL And @EndDate Is NULL),InsertDatetime,@EndDate) )

    文章出處:https://www.dotblogs.com.tw/shadow/2015/12/04/163534


    高級打字員的技術雲

    Convert C# to VB.NET

    /*If my concept is wrong ,please correct me.Thanks.*/

    2015年12月10日 上午 03:22