我經常撰寫許多 PowerShell 腳本,盡量把我日常的工作自動化,這當中經常需要登入一些服務,所以在我的腳本中經常會出現密碼等敏感資料,這些資料如果直接寫在腳本中,通常會有一些風險,所以我通常會對這些敏感資料加密處理,確保這些密碼不會被旁人一眼看穿。這篇文章我就來說說我是怎樣處理這些敏感資料的。
加密處理
基本上,在 PowerShell 之中,我們可以使用 ConvertTo-SecureString
來將字串轉換成安全字串,確保像是密碼這類的資訊可以受到很好的保護。以下 PowerShell 腳本示範如何將一個字串轉換成安全字串:
$securepwd = ConvertTo-SecureString -String 'YourStrongPassword' -AsPlainText -Force
上述寫法會比較不安全,因為你在執行時,文字將會出現在 PowerShell 的歷史紀錄中!比較安全的寫法應該是:
$securepwd = ConvertTo-SecureString -AsPlainText -Force
輸入的過程會要求你輸入密碼:
cmdlet ConvertTo-SecureString at command pipeline position 1
Supply values for the following parameters:
String:
你也可以用以下命令從 Console 視窗輸入一個字串並產生安全字串:
$securepwd = Read-Host -AsSecureString
基本上你從上述命令拿到的 $securepwd
是無法印出來的,那是一個加密過的安全字串,其 .NET 的型別為 System.Security.SecureString
!
若要將這份安全字串轉換成一般字串,可以使用 ConvertFrom-SecureString
,如下:
$encryptedpwd = ConvertFrom-SecureString -SecureString $securepwd
這裡的 $encryptedpwd
就是一個加密過的字串,其內容如下:
01000000d08c9ddf0115d1118c7a00c04fc297eb01000000fce6da1b4890e6478a9ee3180844e27400000000020000000000106600000001000020000000e23dcbe15ad7656150ea7d4630ce2c8ac92cf78e8c15c8332e3356b54c5c4ab9000000000e80000000020000200000002b758f55072729a191d37d151f606b7c4832eb54a09ce4f398a0a94c1cddb4fa300000001a8d7a9731e4012da77cff46e33ce22f9292d3cdc3974d1d0995ee90b69343d0f72c1d62cf4f6ceffafcf56a6d985d034000000082afd2b1a6f6406030d91c952b51736d99c32e6da161459db1ebe085c3acaab3d8091fc6fb5b62929c4dd70d5efece07c91518dea632b72ec4e9e7b52571a7af
注意: 你每次執行 ConvertTo-SecureString
所產生的安全字串都會不一樣,預設他會用 Windows Data Protection API (DPAPI) 來加密這個安全字串。
有了這段加密過的字串,你就可以將它寫入檔案中或是放在 PowerShell 腳本中,任何「人類」看到這段字串不可能快速記憶下來,就算真的「拍照」下來,在別台電腦依然無法解密,因為加密的金鑰是寫在本機電腦中的,所以有一定的安全性!
解密處理
你可以想像一下,我們在腳本中現在有了這一段:
$encryptedpwd = '01000000d08c9ddf0115d1118c7a00c04fc297eb01000000fce6da1b4890e6478a9ee3180844e27400000000020000000000106600000001000020000000e23dcbe15ad7656150ea7d4630ce2c8ac92cf78e8c15c8332e3356b54c5c4ab9000000000e80000000020000200000002b758f55072729a191d37d151f606b7c4832eb54a09ce4f398a0a94c1cddb4fa300000001a8d7a9731e4012da77cff46e33ce22f9292d3cdc3974d1d0995ee90b69343d0f72c1d62cf4f6ceffafcf56a6d985d034000000082afd2b1a6f6406030d91c952b51736d99c32e6da161459db1ebe085c3acaab3d8091fc6fb5b62929c4dd70d5efece07c91518dea632b72ec4e9e7b52571a7af'
接下來就是在要使用密碼的時候,將他先轉回安全字串,如下:
$securepwd = ConvertTo-SecureString -String $encryptedpwd
注意: 你在執行 ConvertTo-SecureString
時,如果跟加密時使用的電腦不同一台,那麼就無法成功轉成安全字串,你將會得到 ConvertTo-SecureString : Key not valid for use in specified state.
錯誤訊息!
如果你想要將安全字串轉換回原始字串內容,就稍微麻煩一點,步驟如下:
-
先取得 System.Runtime.InteropServices.Marshal
類別實例
$Marshal = [System.Runtime.InteropServices.Marshal]
-
使用 Marshal::SecureStringToBSTR
將安全字串轉換成 BSTR (unmanaged binary string)
$Bstr = $Marshal::SecureStringToBSTR($securepwd)
-
使用 Marshal::PtrToStringAuto
將 BSTR 轉換成一般字串
$plaintext = $Marshal::PtrToStringAuto($Bstr)
-
最後使用 Marshal::ZeroFreeBSTR
釋放 BSTR 的資源
$Marshal::ZeroFreeBSTR($Bstr)
另外還有一種方法可以將安全字串轉換回原始字串內容,就是使用 PSCredential
物件幫忙解開密碼:
-
先透過 New-Object System.Management.Automation.PSCredential
建立一個 PSCredential
物件
$credential = New-Object System.Management.Automation.PSCredential('username', $securepwd)
-
然後透過 GetNetworkCredential()
方法取得 NetworkCredential
物件,並透過 Password
屬性取得明文密碼
$plaintext = $credential.GetNetworkCredential().Password
如果你使用 PowerShell 7.3+ 的話,還可以很方便的使用 ConvertFrom-SecureString
搭配 -AsPlainText
來將安全字串轉換回原始字串內容,如下:
ConvertFrom-SecureString -SecureString $secureString -AsPlainText
使用 PSCredential 登入服務
事實上,這個安全字串被使用在許多含有登入機制的服務中,你只要把安全字串轉成 PSCredential
物件,就可以使用在許多地方,例如:
$credential = New-Object System.Management.Automation.PSCredential('username', $securepwd)
我以登入 Azure AD 為例,只要你能拿到 PSCredential
物件,就可以使用 Connect-AzureAD
來登入 Azure AD,如下:
Connect-AzureAD -Credential $credential
我再以 Microsoft Online 的 PowerShell 為例,你可以使用 Connect-MsolService
來登入,如下:
Connect-MsolService -Credential $credential
如此一來就非常方便了!
總結
這篇文章我介紹了如何在 PowerShell 中對機敏字串進行加解密處理,並且使用 PSCredential
物件來登入服務,這樣可以讓我們的腳本更加安全!
不過,你一定要清楚的知道,如果你的腳本被別人拿走的話,還是有機會取得你的「原始密碼」內容的,但前提是必須使用同一台電腦操作才行,所以還算安全。
當然,你也可以將 $encryptedpwd
(安全字串的 String 型態) 儲存到另一個獨立的檔案中,或是放進 Key Vault 裡面,以增強安全性。
相關連結