PowerShell 指令碼中的密碼

sparkdev發表於2017-08-01

引言

筆者在《PowerShell 遠端執行任務》一文中提到了在指令碼中使用使用者名稱和密碼的基本方式:

$Username = 'xxxx'
$Password = 'yyyy'
$Pass = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$Pass

上面的程式碼僅僅是能工作而已,因為在稍有安全性要求的環境中都不會允許明文密碼的出現。本文將介紹在 PowerShell 指令碼中如何以比較安全的方式使用密碼。

把密碼轉為 SecureString

先來了解下面兩個概念:

SecureString
Encrypted Standard String

SecureString 是 .net 中的一個型別,它是為了解決安全性而設計出來的一種特殊的字串型別。比如你使用一個密碼字串建立 SecureString 物件,你無法透過這個物件還原出原來的密碼字串,但是卻可以把 SecureString 物件當做密碼使用。
Encrypted Standard String 是指經過加密後的一個字串。

ConvertTo-SecureString 命令可以透過明文的字串建立 SecureString 物件:

$SecurePwd = ConvertTo-SecureString "123456" -AsPlainText -Force

然後再使用 $SecurePwd 建立 Credential 等身份資訊。這種方式就是筆者在引言部分使用的方法,這是不安全的,因為任何能夠檢視指令碼的人都能從中找出密碼。

把 SecureString 轉為加密字串

透過 ConvertFrom-SecureString 命令,我們可以把一個 SecureString 物件轉換成一個 Encrypted Standard String(加密後的一個字串),然後儲存到檔案中。在建立 Credential 時直接使用前面儲存的檔案,從而避免明文密碼在系統中出現。

$SecurePwd = ConvertTo-SecureString "123456" -AsPlainText -Force
ConvertFrom-SecureString $SecurePwd

上圖顯示 ConvertFrom-SecureString 命令生成的加密字串,我們把它儲存到文字檔案中:

ConvertFrom-SecureString $SecurePwd | Out-File "D:\pwd.txt"

看看內容:

好了,接下來就可以直接使用 pwd.txt 檔案了。

一種看起來比較正常,也很安全的推薦用法:

Read-Host "Enter Password" -AsSecureString |  ConvertFrom-SecureString | Out-File "D:\pwd.txt"

執行這行命令,會要求你輸入密碼:

此處使用鍵盤輸入代替了明文的密碼字串。

介紹了 ConvertFrom-SecureString 命令的用法後就可以介紹 ConvertTo-SecureString 命令的另外一個用法,把加密字串轉換成 SecureString 物件:

$f = "D:\pwd.txt"
$SecurePwd = Get-Content $f | ConvertTo-SecureString
$SecurePwd.Length

這次我們把 pwd.txt 檔案中的內容透過 ConvertTo-SecureString 命令重新生成 SecureString 物件。最後透過 Length 屬性檢查了密碼的長度。

下圖概括了本文中主要術語和命令的關係:

應用密碼的正確姿勢

下面是在指令碼中使用密碼的建議做法:

# 生成並儲存密碼檔案
Read-Host "Enter Password" -AsSecureString | ConvertFrom-SecureString | Out-File "D:\pwd.txt"
# 使用密碼檔案建立 Credential 資訊
$f = "D:\pwd.txt"
$Cred = New-Object -TypeName System.Management.Automation.PSCredential `
                   -ArgumentList UserName, (Get-Content $f | ConvertTo-SecureString)

這種用法也有不足之處,就是隻能在生成 pwd.txt 檔案的機器上使用這個檔案。如果把它複製到其它的機器上,執行 Get-Content $f | ConvertTo-SecureString 時就會報錯:

這是一種安全性限制,如果我們想在其它機器上使用 pwd.txt,就得了解些高階的用法!

高階玩法

ConvertTo-SecureString 和 ConvertFrom-SecureString 命令都支援選項 -Key。在處理密碼時透過使用 Key 選項可以提供額外的安全性,並且允許在不同的環境中使用密碼檔案。

先生成 32 位的 Key 並儲存在檔案 AES.key 中:

$keyFile = "D:\aes.key"
$key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key)
$key | out-file $keyFile

使用 Key 生成並儲存密碼檔案:

Read-Host "Enter Password" -AsSecureString | ConvertFrom-SecureString -key $key | Out-File "D:\pwd.txt"

使用密碼檔案建立和 Key 檔案建立 Credential 資訊:

$userName = "YourUserName"
$passwdFile = "D:\pwd.txt"
$keyFile = "D:\aes.key"
$key = Get-Content $keyFile
$Cred = New-Object -TypeName System.Management.Automation.PSCredential `
                   -ArgumentList $userName, (Get-Content $passwdFile | ConvertTo-SecureString -Key $key)

透過這種方法,把 pwd.txt 和 aes.key 檔案複製到其它的機器上也是可以工作的。但是我們需要額外維護一個 key 檔案的安全,這一般透過設定檔案的訪問許可權就可以了。

總結

PowerShell 提供的安全選項使我們可以避免在指令碼中直接使用明文的密碼,把密碼加密後儲存在檔案中的好處是可以透過檔案的許可權管理進行安全性控制。而使用 Key 選項則可以對上述用例進行擴充套件,從而支援更多的使用場景。但是帶來的不便是我們需要另外維護一個機密的 Key 檔案。從這點也可以看出,所謂的安全性其實是由安全機制和使用者一起來保證的!無論多麼安全的機制,在使用者洩露了認證資訊的情況下都是沒有意義的。

相關文章