在設計資料庫相關程式時,連線字串最好能以加密方式存在config檔案裡;再進一步,最好連解密字串的機制都封裝在特定的資料存取元件中,開發人員及呼叫端程式只需傳入SqlCommand或更高階的抽象化資料物件,就可以完成資料庫存取作業,不必也不能得知連線字串的相關細節。

只是依我自己的實務經驗,有時直接傳連線物件(SqlConnection)給呼叫端是較省事的做法(丟一個連線給你自己玩,別來煩我! 是有點不負責任,但元件開發者未必有時間陪著在每個案子中抱著各式不同的需求打滾),連線丟出去了,呼叫端來個SqlConnection.ConnectionString會不會就讓辛苦加密保護的連線字串瞬間曝光呢?

答案是不會,但也可能會!

SqlConnection中有個屬性Persist Security Info,預設值為false,意思是使用SqlConnection.ConnectionString取得的連線字串,密碼的部分會被移除。

既然如此,為什麼又說可能會呢? 經過實測的結果,這個去除密碼的動作,在SqlConnectoin.Open()後才會發生效果(我猜是要等到密碼用過後才將它去掉,其實這可以用設內用外用兩組字串來克服,但SqlConnection的行為是如此設計),若是傳回尚未開啟的SqlConnection,連線字串會原原本本傳回,就失去保護效果囉!

所以,如果在設計上資料存取元件要傳出可用連線給呼叫端,切記"開了再上",就可以靠這個機制多少提供基本的防護,但最安全的方式還是用資料存取層將企業邏輯與實體資料存取完全隔離開來,只是要達成這個理想得付出些代價就是了。

以下是簡單的ConnectionString密碼隱藏效果測試碼:

static void TestConnString()
{
    SqlConnection cn = 
        new SqlConnection("Data Source=(local); Initial Catalog=myDB; 
User Id=user1; Password=pwd;"
);
    Console.WriteLine("Before: " + cn.ConnectionString);
    cn.Open();
    SqlCommand cmd = new SqlCommand("SELECT GETDATE() AS D", cn);
    SqlDataReader dr = cmd.ExecuteReader();
    dr.Read();
    Console.WriteLine("Now={0:yyyy-MM-dd HH:mm:ss}", dr["D"].ToString());
    Console.WriteLine("After: " + cn.ConnectionString);
    cn.Close();
}

【延伸閱讀】MSDN裡關於ADO.NET連線保密的說明


Comments

# by Alfred

站長你好: 實在不知道去哪裡留言,因此只好寫在這篇的comment,希望您別介意。小弟是您的忠實讀者,雖然大多數都看不太懂就是了。我有個問題,不知道您是否能給我點方向及意見。 老闆要抓取SQL2005的連線數,用類似像MRTG的方式,作成歷史流量及圖表,方便以後可以判斷SQL server的loading。但是SQL2005似乎已經不支援SNMP,讓我有點不知所措,找了很多資料卻沒有相關的方式,不知道您是否可以給小弟一點方向? 上面留下小弟的gmail,希望您在空閒之餘能夠稍加回覆,感激不盡...

# by Jeffrey

to Alfred, 我在監控DB的領域的研究不多,原因是現在的工作團隊中有專職的DBA,我就乖乖閃開讓專家來(當然,帶著幸福的笑容)。 Google了一下,似乎SQL 2000+就不再支援SNMP了,但有要錢的軟體(http://www.wtcs.org/informant/SQL/SQL-overview.htm)可為SQL加上SNMP功能(連SQL2008都支援),你可以參考看看。另外,或許你也可試試在TechNet論壇發問看看(http://social.technet.microsoft.com/forums/zh-TW/sqlservermanagementzhcht/threads/),說不定論壇上的SQL專家們還有其他的門路。

# by Tom

請問黑暗大,目前在設計DB連線字串封裝查到這邊,我的目的是要讓Junior不要在webconfig看到資料庫連線,所以我將連線字串封裝成DLL,放到private Nuget 供他們下載。 不知道這樣方向正不正確 ? 但這樣我不太清楚這個DLL要怎麼針對不同環境來做切換 譬如:連到localdb、連到測試機、連到正式機 因為以前在webconfig可以區別 release debug 等 @@

# by Jeffrey

to Tom, 你是指將連線字串Hard-Code進程式碼,編譯成元件讓其他開發者安裝嗎? 這種做法較少見,聽起來要為正式台跟測試台各編譯一顆DLL。 至於放進DLL會比較安全嗎? 我覺得菜鳥工程師只要經驗稍足,就不難反組譯或寫段程式從DLL挖出連線字串,基本上你很難防止拿到元件的人從中挖出機密,除非機密基本不在元件裡。若使用web.config,倒是可區分正式及測試設定,正式DB設定要做到開發者無法取得,至於測試DB設定,除非禁止開發者直接操作測試機,要假設開發者一定能知道,改去評估如何避免風險或防堵作惡。 若希望開發者連測試DB連線字串都不知道,我想到的做法是中間再隔一層WebAPI(要鎖IP或加認證),非核心開發者只能經由WebAPI存取DB,開發測試時不需要DB帳號密碼,就沒有外洩風險。

Post a comment