# 資料庫欄位加密以及金鑰移轉的方法,使用 Sql Server always encrypted 資料庫加密 ## 資料庫加密的用途 資料庫加密可以達到幾個目的 1. 資料原始檔被竊取,但沒有拿到金鑰時,無法正確解密,看不到機密資料 2. 資料庫加密可以避免未經授權的系統管理者取得資料 舉例來說,如果資料庫中的資料加密了,系統管理員在資料庫中檢視資料,看到的都是加密的內容,需要擁有解密憑證(金鑰)才能看到真正的資料。 * 如果目標是確保組織中的 DBA 無法存取敏感性資料,建議使用角色隔離管理金鑰。 :::info 只在應用程式伺服器存放金鑰,資料庫系統的伺服器作業系統中;或是資料庫管理者的帳號無法取得拿不到金鑰即可 ::: * 如果目標是限制雲端管理員 (而不是內部部署 DBA) 存取敏感性資料,可建議不使用角色隔離來管理金鑰。 參考資料:[金鑰管理角色](https://docs.microsoft.com/zh-tw/sql/relational-databases/security/encryption/overview-of-key-management-for-always-encrypted?view=sql-server-ver16#key-management-roles) ## Sql Server 版本比較,共五個版本 1. SQL Server Enterprise 2. SQL Server Standard 3. SQL Server Web Edition 4. SQL Server Developer Edition 5. Express Edition Express 版本可以使用 Always Encrypted 資料庫欄位加密功能 ![](https://i.imgur.com/XF5Td5h.png) 但 Express 版本沒有把備份檔加密的功能 ![](https://i.imgur.com/88dg1od.png) 其他各版本功能比較與差異詳見以下連結 https://docs.microsoft.com/zh-tw/sql/sql-server/editions-and-components-of-sql-server-version-15?view=sql-server-ver16 ## 要解決的問題 1. 能不能做全資料庫加密? (自動增加的 id 好像不行) 1. 如何確認資料已被加密? (不要帶金鑰連線,或是按加密的資料行檢查加密狀態) 1. 如何觀看解密資料? 2. 如何改回未加密的狀態? (有金鑰的狀態,按加密資料行,選成純文字) 3. 加密金鑰被放在哪裡? (預設位置在 Get-ChildItem -Path Cert:\CurrentUser\My ) 4. 加密金鑰的備份還原的方法? 5. 被加密後的資料,能不能用 where and or like 等等條件式搜尋? (好像都不行) 6. 加密後的運作效能評估? (新增、修改、查詢都需要評估) ## 加密金鑰盤點以及存放位置 可以在資料庫輸入以下語法查詢 ```sql= SELECT * FROM sys.column_master_keys; SELECT * FROM sys.column_encryption_keys SELECT * FROM sys.column_encryption_key_values ``` 查詢結果範例 ``` CMK_Auto1 1 2024-02-22 22:31:17.280 2024-02-22 22:31:17.280 MSSQL_CERTIFICATE_STORE CurrentUser/my/D67B7EB7209277012DFB72A90C9D4043E227B136 0 NULL ``` ## 解密資料方法1 圖形介面管理工具 GUI 登入介面,要選 其他連線參數(Additional Connection Parameters) 頁籤,加入「Column Encryption Setting = Enabled」 這樣連線進去才看得到資料,沒加的話會看到加密的資料 ## Always Encrypted 的效能影響 Always Encrypted 的加解密不是在資料庫進行,而是在用戶端(client)的應用程式 or GUI 圖形介面工具,所以大部分的效能額外負荷是在資料庫上看不出來,除了加密和解密作業成本之外,用戶端其他的效能額外負荷來源如下: * 額外往返資料庫以擷取查詢參數的中繼資料。 * 呼叫資料行主要金鑰存放區以存取資料行主要金鑰。 參考來源:[控制 Always Encrypted 的效能影響](https://docs.microsoft.com/zh-tw/sql/connect/odbc/using-always-encrypted-with-the-odbc-driver?view=sql-server-ver16#controlling-the-performance-impact-of-always-encrypted) --- ## 實際執行加密 跟著微軟教學 [教學課程:開始使用 Always Encrypted](https://learn.microsoft.com/zh-tw/sql/relational-databases/security/encryption/always-encrypted-tutorial-getting-started?view=sql-server-ver16&tabs=ssms) 可以正常做到資料庫加密,但加密完後 Visual Studio 的連線字串要加上 ```Column Encryption Setting=Enabled;``` 才能在程式內解密,並且和 EntityFramework 搭配,如果加上去後發現沒有解密,可以重開整個 visual studio 讓程式重新讀取一次 以下是包含 Column Encryption 的完整的連線字串範例 ` <add name="ContosoHREntities" connectionString="metadata=res://*/Models.Model1.csdl|res://*/Models.Model1.ssdl|res://*/Models.Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=localhost\SQLEXPRESS;initial catalog=ContosoHR;Column Encryption Setting=Enabled;integrated security=True;encrypt=False;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" /> ` * EF6資料庫加密 優先閱讀這篇 sql server 加密和ef程式連動的方法 https://dotblogs.com.tw/yc421206/2019/05/18/ef6_connect_sql_server_2016_always_encrypted * 再閱讀同作者這篇 加密後的使用限制 https://dotblogs.com.tw/yc421206/2019/05/31/ef6_connect_sql_server_2016_always_encrypted_limit_solution --- ## 匯出金鑰 如果要更換電腦,金鑰檔消失的話會造成無法讀取也無法解密,這非常重要 * 匯出的方法:在開始功能表輸入 certmgr.msc 或 mmc ,開啟 mmc 工具 ![image](https://hackmd.io/_uploads/BJ_JTc2XA.png) * 開啟 新增/移除 嵌入式管理單元 ![image](https://hackmd.io/_uploads/S1JZ6q2XR.png) * 左邊捲到最下面,選擇憑證後,勾其中一個(看當初金鑰放哪,不知道就選三次都加進來) ![image](https://hackmd.io/_uploads/Hk5Z0c2m0.png) * 以我來說,是在(目前的使用者)個人 > 憑證 ,找到 Always Encrypted Auto Certificate 1 和 2 的金鑰,按右鍵匯出金鑰 ![image](https://hackmd.io/_uploads/SJEK392XA.png) * 匯出的 pfx 檔,帶到另外一台電腦,一樣開mmc 憑證,按右鍵選匯入 ![image](https://hackmd.io/_uploads/Sydy1s3m0.png) * 匯入找不到的話,下拉選單記得改成.pfx ![image](https://hackmd.io/_uploads/HJb4Jih70.png) * 使用Sql server management studio 的圖形介面工具查詢時,第一次查可能會出現的畫面 ![image](https://hackmd.io/_uploads/HkX-oKhX0.png) --- ## 移轉資料庫,但是沒有正確移轉金鑰,可能會出現的錯誤訊息 如果資料庫還原到其他電腦時,會出現這樣的訊息,如果出現的話,請參考[](https://) #匯出金鑰 的部分 標題: Microsoft SQL Server Management Studio ------------------------------ 無法解密資料行 '欄位名稱'。 無法使用金鑰存放區提供者 'MSSQL_CERTIFICATE_STORE' 解密資料行加密金鑰。加密資料行的加密金鑰前 10 個位元組為: '99-C1-70-B0-CE-72-B9-60-5B-55'。 在憑證位置 'CurrentUser' 的憑證存放區 'My' 中找不到指紋為 'D12H4W6C77F944W56B45 ' 的憑證。請確認資料庫內資料行主要金鑰定義中的憑證路徑正確,且憑證已經正確地匯入該憑證位置/存放區。 參數名稱: masterKeyPath ------------------------------ 錯誤畫面 ![image](https://hackmd.io/_uploads/BkRjaK370.png) --- * Always Encrypted 介紹 https://docs.microsoft.com/zh-tw/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-ver16 * 使用 Always Encrypted 與 SQL Server Management Studio 查詢資料行 https://docs.microsoft.com/zh-tw/sql/relational-databases/security/encryption/always-encrypted-query-columns-ssms?view=sql-server-ver16 * 建立完整資料庫備份 (含加密備份的內容) https://docs.microsoft.com/zh-tw/sql/relational-databases/backup-restore/create-a-full-database-backup-sql-server?view=sql-server-ver16 * Always Encrypted 的金鑰管理概觀 https://docs.microsoft.com/zh-tw/sql/relational-databases/security/encryption/overview-of-key-management-for-always-encrypted?view=sql-server-ver16 * 使用 SQL Server Management Studio 輪替 Always Encrypted 金鑰 https://docs.microsoft.com/zh-tw/sql/relational-databases/security/encryption/rotate-always-encrypted-keys-using-ssms?view=sql-server-ver16 * 搭配 .NET Framework Data Provider for SQL Server 使用 [永遠加密] https://docs.microsoft.com/zh-tw/sql/relational-databases/security/encryption/develop-using-always-encrypted-with-net-framework-data-provider?view=sql-server-ver16 * [Day07] 資料儲存安全(SQL Always Encrypted)上 https://ithelp.ithome.com.tw/articles/10187092 * [Day08] 資料儲存安全(SQL Always Encrypted)下 包含 .NET程式端寫入資料 .NET專案目標framework必須為.NET 4.6 https://ithelp.ithome.com.tw/articles/10187234 * [SQL Server]Always Encrypted筆記(SQL Server 2016新功能) https://dotblogs.com.tw/stanley14/2016/03/19/165914 * [實作] SQL 資料加密(Always Encrypted) https://dotblogs.azurewebsites.net/BigCow/2019/12/26/155226 * 使用SQL Server 2016的Always Encrypt功能防止系統管理員讀取私密性資料 https://www.uuu.com.tw/Public/content/article/19/20190805.htm