The Will Will Web

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

如何在 PowerShell 對機敏字串進行加解密處理

我經常撰寫許多 PowerShell 腳本,盡量把我日常的工作自動化,這當中經常需要登入一些服務,所以在我的腳本中經常會出現密碼等敏感資料,這些資料如果直接寫在腳本中,通常會有一些風險,所以我通常會對這些敏感資料加密處理,確保這些密碼不會被旁人一眼看穿。這篇文章我就來說說我是怎樣處理這些敏感資料的。

Encryption

加密處理

基本上,在 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. 錯誤訊息!

如果你想要將安全字串轉換回原始字串內容,就稍微麻煩一點,步驟如下:

  1. 先取得 System.Runtime.InteropServices.Marshal 類別實例

    $Marshal = [System.Runtime.InteropServices.Marshal]
    
  2. 使用 Marshal::SecureStringToBSTR安全字串轉換成 BSTR (unmanaged binary string)

    $Bstr = $Marshal::SecureStringToBSTR($securepwd)
    
  3. 使用 Marshal::PtrToStringAuto 將 BSTR 轉換成一般字串

    $plaintext = $Marshal::PtrToStringAuto($Bstr)
    
  4. 最後使用 Marshal::ZeroFreeBSTR 釋放 BSTR 的資源

    $Marshal::ZeroFreeBSTR($Bstr)
    

另外還有一種方法可以將安全字串轉換回原始字串內容,就是使用 PSCredential 物件幫忙解開密碼:

  1. 先透過 New-Object System.Management.Automation.PSCredential 建立一個 PSCredential 物件

    $credential = New-Object System.Management.Automation.PSCredential('username', $securepwd)
    
  2. 然後透過 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 裡面,以增強安全性。

相關連結

留言評論