The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何打造符合個資法規的網站系統 — 以 ASP.NET 為例

為因應個資法的來臨,筆者去年曾投稿資安人電子雜誌關於「個人資料保護法」的文章,主要是站在開發人員的角度進行思考如何打造符合個資法規的網站系統,文章中結合了我近幾年對個資法的瞭解與網站實務開發經驗,明確告知開發人員如何做好自己該做的事,千要不要認為個資法只是一個資安政策,而是你我必須認真看待與面對的日常工作。本文已於今年一月刊載於資安人電子雜誌82期,由於資安人電子雜誌是付費版的電子雜誌,礙於許多開發人員所處公司可能沒有訂閱該雜誌,今日得到資安人電子雜誌的同意,允許我將此文全文轉載於我的部落格,分享給開發人員。如讀者對資安相關議題有興趣,建議也可考慮加入資安人電子雜誌的付費會員,即時獲得最新的資安訊息。

---

新版個資法來勢洶洶,個資法施行細則修正草案也已經出爐,在不久的將來所有會接觸到個資的軟體系統也將面臨前所未有的考驗,開發人員必須趕緊跟上腳步,除了釐清個資法對你帶來的影響外,因應個資法所帶來的技術衝擊也必須進一步瞭解,以免當這些硬梆梆的法律條文出現時,反而不知道如何將個資法的種種要求落實在既有的系統之中,本文的宗旨就在於提醒各位開發人員,面臨新版個資法的衝擊,應該提早準備哪些必學的知識與技術。

在新版個資法中雖然有非常高額的罰款,同一原因事實造成多數人損害最高可處罰 2 億元,但是這些損害賠償責任與罰則並非此法的重點,其重點在於希望民眾與企業建立「個資有價」之觀念,以及「資訊系統欠缺合理安全措施,即構成隱私權侵害」。「個資有價」之觀念是希望使用者建立起個資有價的意識,當個人資料外洩時,可以向企業提出求償,不但如此,企業還被要求要負起舉證責任,對企業來說,這等於是一顆不定時炸彈,因為個資外洩可能造成的原因很多,如果真要企業做到 100% 的防堵個資外洩是不太可能的。還好,在新版個資法施行細則草案中已經明確定義出「舉證責任」的範圍 (新版個資法第九條),只要企業能提出這些保護個資的部分或全部舉證資料,就能有效的避免損害賠償責任與罰則的發生。

以下摘錄新版個資法施行細則草案第九條的內容:

第九條 本法所稱適當安全維護措施、安全維護事項或適當之安全措施,指公務機關或非公務機關為防止個人資料被竊取、竄改、毀損、滅失或洩漏,採取技術上及組織上之必要措施。

前項必要措施,應包括下列事項:
一、成立管理組織,配置相當資源。
二、界定個人資料之範圍。
三、個人資料之風險評估及管理機制。
四、事故之預防、通報及應變機制。
五、個人資料蒐集、處理及利用之內部管理程序。
六、資料安全管理及人員管理。
七、認知宣導及教育訓練。
八、設備安全管理。
九、資料安全稽核機制。
十、必要之使用紀錄、軌跡資料及證據之保存。
十一、個人資料安全維護之整體持續改善。

第一項必要措施,以所須支出之費用與所欲達成之個人資料保護目的符合適當比例者為限。


在這些必要措施中,有許多都與開發人員沒有直接關係,但是第九點「資料安全稽核機制」與第十點「必要之使用紀錄、軌跡資料及證據之保存」正是程式開發人員可以努力的部分,以下我就針對這兩點做出各種可行的技術解決方案供開發人員參考。

在這兩項必要措施裡,需注意到與個資保護相關的技術很多,主要有身份認證(Authentication)角色授權(Authorization)存取控制資料加密資料保護安全設定系統操作紀錄個資變更歷史紀錄等等,以下我們將一一介紹需要注意的地方,以及可以採用的防護技術。

 

身份認證(Authentication)

建置資訊系統時如果會牽扯到個資,最基本的防護原則就是要做到身份認證,不讓未經授權的人使用或進入該系統取得個人資料,開發人員絕不能假設系統網址只有自己人知道而不做出任何防護,要是個資被受侵害的使用者告上了,企業這方若無法提出任何身份認證的實作證據,那可是完全說不通的,只有乖乖挨罰的份了。

在ASP.NET中,最常見的身份驗證技術就是使用FormsAuthentication類別進行實作,當處理完基本的帳號、密碼驗證正確後,便可透過以下程式碼賦予目前使用者一個「已登入」的身份:

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
	strUsername,  // 登入帳號
	DateTime.Now,
	DateTime.Now.AddMinutes(30),
	isPersistent,
	userData,
	FormsAuthentication.FormsCookiePath); 

// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket); 

// Create the cookie.
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));

而在你的系統中,要辨識出使用者是否已成功通過身份驗證,則可利用以下程式碼進行判斷:

if(User.Identity.IsAuthenticated)
{
	Response.Write("您現在是已登入狀態。");
} 

實作細節可參考筆者的【概略解釋 Forms Authentication 的運作】文章。

NOTE
筆者早期也曾經遇過有開發人員將「身份驗證」的工作直接實作在「用戶端」直接以JavaScript驗證使用者輸入的帳號、密碼,這是完全行不通的作法,因為駭客很輕易的就可以關閉或修改用戶端的JavaScript程式來跳過這個驗證需求。因此開發人員必須特別注意,所有認證控制措施都必須在伺服端進行,絕不可使用JavaScript在前端做認證。

 
除此之外,當認證控制措施發生錯誤時(例如當下連不上Active Directory無法進行驗證),也要能確保系統不會被任意存取,絕不可因為驗證失敗發生後卻又能進入系統等情事發生。

在身份認證的部分,以下規則也是可以讓開發人員參考的部分:

  • 身份驗證的時候,應該完整記錄登入成功與登入失敗的資訊,並定時追蹤登入失敗的資訊,確保系統安全。
  • 儲存使用者密碼進資料庫時,不應用明文儲存,開發人員應該將使用者的密碼作雜湊(Hash)處理,以免資料庫外洩時而導致密碼被駭客擷取,進而引發個資外洩的疑慮。
  • 在執行取得大量個資時(例如匯出會員資料),必須要求使用者重新認證一次,以確保為本人操作系統。
  • 使用者登入一段時間且沒有任何使用記錄時,應該主動將使用者登出。
  • 系統中所有認證資訊(例如連結資料庫的帳號密碼)都必須加密存放於應用程式之外,不可直接存放於原始碼中。

 

角色授權(Authorization)與存取控制(Access Control)

當我們做到身份認證後,接下來就必須確保使用者只能存取權限內的系功能統與資料,以維護系統的完整性與機密性。從實務上來說,我們通常會在資訊系統中設定幾個特定的角色,並在設定系統操作權限時將權限的設定都套用在角色上,最後再對登入系統的操作人員設定其隸屬的角色,如此一來可以簡化權限設定上的複雜度。

就Web應用程式來說,存取控制要注意的地方不僅僅是「特定功能可否使用」而已,有些存放在Web伺服器上的檔案也是必須要控管的部分,所以除了要針對後台功能進行控管外,針對可以透過URL直接存取到的檔案也必須加以限制存取材行。

舉個之前筆者曾經輔導過的一個案例,當時客戶的網站裡的確有實作角色授權與存取控制,但是只針對特定頁面與功能做限制,卻忘了針對「靜態檔案」的部分做限制,當時他們網站的後台有上傳檔案的功能,而上傳的路徑為網站根目錄下的 /Uploads/File/ 目錄,而這個目錄並沒有做任何的存取控制,所以即便未經驗證的使用者無法操作後台功能,但是卻能透過 URL 直接存取這些已上傳的檔案,例如:http://xxx.com/Uploads/File/Member.xls,如果這些上傳的檔案包括個資的話,那就非同小可了。

你可能會覺得好奇,「未經驗證的使用者」怎麼會知道這些可以直接下載檔案的URL是什麼呢?難道是這些已授權的使用者洩漏出去的嗎?許多使用者並不知道「未經驗證的使用者」其實還包括「搜尋引擎機器人」,假設你的瀏覽器安裝了搜尋引擎所提供的瀏覽器工具列(Browser Toolbar),當你在瀏覽網站的同時也會同時將你瀏覽的網址傳送回他們的伺服器,好讓他們能夠進一步檢索任何他們原本檢索不到的網頁,當然也包括這些未經身份驗證就能存取的「靜態檔案」。

要防止搜尋引擎機器人來抓取特定目錄下的資料是有業界標準的,我們只要在網站根目錄下新增一個robots.txt 文字檔,並定義特定目錄不允許「搜尋引擎機器人」進行存取。假設我們要預設允許所有搜尋引擎前來抓取網頁,但要限制特定目錄(/Uploads/)不允許存取的話,各位可以參考以下 robots.txt 的內容範例:

User-agent: *
Disallow: /Uploads/

這種設定方式只是禮貌性的告知那些如何規定的搜尋引擎機器人來限制抓取的路徑,事實上真的要抓取網頁檔案還是可以的,因此這個技巧也僅適用於「搜尋引擎」的部分而已,網站系統要真正做到安全,還必須更嚴格的來限制其存取,才能真正確保網站系統安全。

在ASP.NET裡內建了一個非常簡單的方法,只要修改web.config設定檔,就能限制特定URL一定要先通過身份驗證才能存取該檔案。以下範例是假設你想要限制 /Uploads/ 目錄一定要先通過驗證才能進行存取,就可以將以下設定套用在你網站根目錄下的 web.config 設定檔之中:

<?xml version="1.0"?>
<configuration>
<location path="Uploads">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>
</configuration>

請注意:使用這種驗證設定,必須使用ASP.NET標準的驗證模式才能生效,例如使用FormsAuthentication或透過Windows驗證的方式都可以。

在去年,人事行政局曾經發生過個資外洩的事件,當時他們把僅限公務人員才能下載的資料放置在一個公開的FTP伺服器上,然後再把FTP的存取路徑設定在網站資料庫中,雖然該網站需要登入才看的到有哪些檔案可下載,但是卻沒注意到檔案放置在一個可公開存取的FTP伺服器上,還進一步被Google搜尋引擎建立了快取資料,即便檔案已儘速刪除,但Google搜尋引擎還是依然留存這些含有個資的資料。

等新版個資法正式生效後,諸如此類的資安事件若再度發生,將會導致企業或組織陷入危機,因此開發人員一定要先建立正確的資安防護觀念,才能真正確保系統無虞。在資安的領域中我們常提到,一個資訊系統的資安強度,取決於系統中最脆弱的一環,在組織裡,即便有再多的個資政策與資安規範,只要開發人員不夠注意,資安人員又沒有掌握到這些細節,稽核人員又查不到這些地方時,個資外洩的風險就會大幅提升。

在存取控制部分,以下規則也是可以讓開發人員參考的部分:

  • 關閉IIS中目錄瀏覽功能
  • 善用ASP.NET角色實作各類權限控管的機制
  • 確認使用者僅能存取權限內的服務
  • 所有存取控制措施必須在伺服器端強制執行
  • 所有存取控制的結果都必須被記錄,包括驗證成功與失敗都應紀錄

 

資料加密

開發一個安全的資訊系統,基本的資料加密工作不可或缺,但資料加密可以區分為幾個不同的範疇,其中叫常見的有「網路傳輸加密」與「資料庫加密」兩個部分。

「網路傳輸加密」部分是為了要確保個人資料在網路傳輸的過程中,不會被有心人士從中攔截,保護個人資料不會輕易外洩,要做到這點其實非常容易,只要在網站伺服器上安裝SSL憑證,就可以輕鬆完成這個任務,但是網站程式也必須特別修改,讓會牽扯到個資功能的頁面強迫進入HTTPS傳輸模式才行,以下是一段範例程式供參考:

protected void Page_Load(object sender, EventArgs e)
{
	if (!Request.IsSecureConnection)
	{
		Response.Redirect(
			Request.Url.AbsoluteUri.Replace("http://", "https://")
		);
	}
}

「資料庫加密」部分就是將重要的機敏資料儲存資料庫之前先將資料加密過再進行儲存,確保儲存個資的原始資料本身是加密過的,這部份依據不同的資料庫系統會有不同的解決方案,在此筆者會以SQL Server作為主要的資料庫系統。

在SQL Server裡已經內建了完整的資料庫加密功能,其最主要的目的在於確保儲存在磁碟中的原始資料本身是加密過的版本,這也代表著任何一份資料庫備份中重要的資料都是加密過的,就算資料庫備份檔被駭客劫走,駭客也無法輕易的解開裡面的內容,以達到保護的目的。

當然,在加解密的過程中會消耗掉一些CPU與記憶體資源,因此不建議將所有資料進行加密儲存,不過我們為了個資法的要求,開發人員可以選擇將牽涉到個人資料欄位都改以加密的方式儲存,確保這些個資都能夠被妥善的保護。

在個資法中已明確列出那些「個人資料」的欄位,其中包括自然人之姓名、出生年月日、國民身分證統一編號、護照號碼、特徵、指紋、婚姻、家庭、教育、職業、病歷、醫療、基因、性生活、健康檢查、犯罪前科、聯絡方式、財務情況、社會活動等等,但除了這些明訂的資料外,任何其他得以直接或間接方式識別該個人之資料也都包含在內,因此當資訊系統在規劃的時候,還是要再次檢視哪些可能構成個資的欄位,並於以加密儲存。

備註:關於技術方面的主題建議可參考MSDN上【SQL Server 加密】文件。

NOTE
由於個資法裡要求企業要負擔舉證責任,你只要能盡可能的保護客戶資料不外洩,就越能夠證明你有心想把個資保護做到最好。

 

資料保護

資料保護與資料加密的概念不太一樣,這裡講的是保護使用者的個人資料不會被輕易取得,開發人員應該建立一些資料保護的資安概念,才能寫出真正對使用者有保障的程式。

在網站裡可能會有許多敏感的個人資料並非儲存在資料庫中,而是儲存在檔案裡,例如網站執行過程若會儲存一些追蹤資訊或是網站應用程式的錯誤處理紀錄,這些追蹤資訊可能會包含個資,在這種情況下,你應該將這些檔案儲存在無法直接透過網站伺服器存取的目錄下,在ASP.NET裡有個特殊的App_Data目錄就是這個用途,對於這些牽涉個資的檔案記錄,開發人員可以選擇將檔案儲存在這個目錄下,確保檔案不會直接透過瀏覽器下載。

我們都知道在設計網頁表單時,大多瀏覽器都有表單自動完成功能(如下圖示),當使用者正在使用的是公用電腦,在網站表單上輸入個資的時候就會被自動記憶下來,如此一來就會有個資洩漏的風險。

開發人員應該在網頁表單上設定關閉自動完成功能,來避免此類個資問題的發生。假設我們有個文字輸入框的HTML如下:

<input type="text" id="textinput" />

要關閉自動完成功能,只要加上autocomplete屬性,並設定為off即可:

<input type="text" id="textinput" autocomplete="off" />

網站伺服器一般來說都有記錄功能,可以將每個HTTP要求的摘要資訊都寫進記錄檔中,其中也包括了所有查詢字串(QueryString),我們都知道表單的送出方法有好幾種,最常見的有GET與POST這兩種,如果你的表單使用GET方法送出的話,所有表單資料都會被串接到QueryString之中,也代表著這些資料全部都會被儲存到網站伺服器的記錄檔中,如果表單的內容牽涉到個資,那麼你的伺服器記錄檔將會是另一個個資洩漏的管道,因此開發人員在撰寫網頁表單時請務必記得調整為POST方法才能確保個資不會被紀錄到網站伺服器的存取記錄(Access Log)之中。

開發網站應用程式,無論如何資料都必須傳到用戶端才能顯示,你可以做到「網路傳輸加密」確保資料傳送的過程中不被擷取,但是資料畢竟還是會儲存到用戶端(瀏覽器)上,如果傳輸的內容包括個資,開發人員應該避免這些資料或頁面被快取在用戶端,如個資必須儲存在用戶端進行快取,也必須實作加密機制,確保個資不會被有心人士輕易取得,而且當這些機敏資料無須使用或過期時,也應立即清除所有快取資料。

 

系統操作紀錄

由於新版個資法要求保存必要之使用紀錄與軌跡資料,因此紀錄完整的操作紀錄非常重要,如此一來可以得知特定人員在特定時間取得了哪些資料。然而留下系統操作紀錄不是什麼難事,怕的是記錄到的資料沒有證據力,那就白費功夫了。尤其系統使用記錄、軌跡資料與證據的保存,細則草案第九條都有明訂,開發人員需與MIS共同制定管理方式。

開發人員基本上可依據「人、事、時、地、物」的原則來對系統進行規劃與設計,如下表是筆者整理一些可能需要記錄的欄位資料:

記錄類型

記錄的欄位或資料

操作人員的帳號、角色

操作的功能與參數

操作的時間點

操作人員的來源IP地址、使用的主機名稱、伺服器的主機名稱

操作執行的結果(如成功或失敗)、查詢條件、資料回傳筆數、回應訊息內容

 

個資變更歷史紀錄

我們會紀錄完整的系統操作紀錄,但這些紀錄應該不會儲存完整的查詢結果資料,如果我們因為個資法的歷史軌跡要求而將完整的查詢結果資料儲存在記錄檔中,將會導致記錄檔佔用了非常大量的磁碟空間,這樣的設計反而失去了系統的彈性。

因此,在實務上我們可以選擇儲存所有個資的變更歷史紀錄,只要牽涉到個資的欄位發生變更時,一樣可以依據「人、事、時、地、物」的原則記錄這些變更歷史,到時只要交叉比對操作紀錄個資異動記錄,就能比對出當時特定人員所取得的個資為何,以達到證據保存之目的。

 

總結

開發人員為了因應這波新版個資法的衝擊,無論如何都必須做出一些改變,尤其是在思維上必須完全站在個資保護的立場來思考系統的規劃與設計,要打造出符合個資法規的網站系統,說難也不難,說簡單也可以很不簡單。

筆者認為,開發人員覺得難的地方在於不知道如何面對個資法的種種要求,這種不確定感會導致大家在開發系統時感覺十分徬徨,不知道怎樣做才是對的,但只要掌握住一些新版個資法的核心原則,相信也能夠安心的開發出符合個資法的系統,筆者在本篇文章中提出幾個可以注意的點,或許無法面面俱到,但只要所有企業都能適度的對新版個資法做出回應,開發人員都能理解並對個資法的要求做出一絲努力,相信就已達成當初立法的初衷,向全民推廣「個資有價」之目的。

留言評論