Powershell

使用 PowerShell 發送包含密碼的安全電子郵件

  • May 28, 2018

我正在實現編寫一個 PowerShell 腳本來發送一封包含密碼的安全電子郵件。我一直在研究實施的好方法,但找不到合適的方法。

**場景是:**一個人請求密碼,腳本會自動生成密碼並發送到這個人的郵箱,這個人使用Outlook打開郵箱。

我的願望是強制使用他的 AD 憑據的人打開電子郵件,但要做到這一點,執行此腳本的帳戶需要擁有此人的證書。因此,這似乎是不可能的。

我的第二個想法是創建一個網頁,密碼請求者可以在其中解密他們通過電子郵件收到的密碼。該網頁需要單點登錄和其他技巧來保護想要登錄的經過身份驗證的使用者。

如果你有更好的想法,可以幫我整理一下嗎?

param(
   $sAMAccount,
   $filePath
)

$RootDSE = [ADSI]("LDAP://RootDSE") 
$SearchForestForPerson = New-Object DirectoryServices.DirectorySearcher 
$SearchForestForPerson.SearchRoot = "GC://" + $RootDSE.rootDomainNamingContext 
$SearchForestForPerson.SearchScope = "subtree" 
$SearchForestForPerson.PropertiesToLoad.Add("distinguishedname") | Out-Null 
$SearchForestForPerson.PropertiesToLoad.Add("mail") | Out-Null 
$SearchForestForPerson.PropertiesToLoad.Add("usercertificate") | Out-Null 
$SearchForestForPerson.Filter = ("(&(objectClass=person)(CN=$sAMAccount))") 
$Recipient = $SearchForestForPerson.FindOne()
$ChosenCertificate = $null 
$Now = Get-Date 
If ($Recipient.Properties.usercertificate -ne $null) { 
   ForEach ($UserCertificate in $Recipient.Properties.usercertificate) { 
       $ValidForSecureEmail = $false 
       $Certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$UserCertificate 
       $Extensions = $Certificate.Extensions 
       ForEach ($Extension in $Extensions) { 
           If ($Extension.EnhancedKeyUsages -ne $null) { 
               ForEach ($EnhancedKeyUsage in $Extension.EnhancedKeyUsages) { 
                   If ($EnhancedKeyUsage.FriendlyName -eq "Secure Email") { 
                       $ValidForSecureEmail = $true 
                       break 
                   } 
               } 
               If ($ValidForSecureEmail) { 
                   break 
               } 
           } 
       } 
       If ($ValidForSecureEmail) { 
           If ($Now -gt $Certificate.NotBefore.AddMinutes(-5) -and $Now -lt $Certificate.NotAfter.AddMinutes(5)) { 
               $ChosenCertificate = $Certificate 
           } 
       } 
       If ($ChosenCertificate -ne $null) { 
           break 
       } 
   } 
}
$keytab = Get-item -Path $filePath
Add-Type -assemblyName "System.Security" 
$MailClient = New-Object System.Net.Mail.SmtpClient "ip.contoso.se" 
$Message = New-Object System.Net.Mail.MailMessage
$Message.To.Add($Recipient.properties.mail.item(0)) 
$Message.From = "noreply@contoso.se" 
$Message.Subject = "Test Unencrypted subject of the message"

$Body = "This is the password for your service account: p4ssw09rd23!"

$MIMEMessage = New-Object system.Text.StringBuilder 
$MIMEMessage.AppendLine("MIME-Version: 1.0") | Out-Null 
$MIMEMessage.AppendLine("Content-Type: multipart/mixed; boundary=unique-boundary-1") | Out-Null 
$MIMEMessage.AppendLine() | Out-Null
$MIMEMessage.AppendLine("This is a multi-part message in MIME format.") | Out-Null
$MIMEMessage.AppendLine("--unique-boundary-1") | Out-Null
$MIMEMessage.AppendLine("Content-Type: text/plain") | Out-Null
$MIMEMessage.AppendLine("Content-Transfer-Encoding: 7Bit") | Out-Null
$MIMEMessage.AppendLine()|Out-Null
$MIMEMessage.AppendLine($Body) | Out-Null
$MIMEMessage.AppendLine() | Out-Null

$MIMEMessage.AppendLine("--unique-boundary-1") | Out-Null
$MIMEMessage.AppendLine("Content-Type: application/octet-stream; name="+ $keytab.Name) | Out-Null
$MIMEMessage.AppendLine("Content-Transfer-Encoding: base64") | Out-Null
$MIMEMessage.AppendLine("Content-Disposition: attachment; filename="+ $keytab.Name) | Out-Null
$MIMEMessage.AppendLine() | Out-Null

[Byte[]] $binaryData = [System.IO.File]::ReadAllBytes($keytab)
[string] $base64Value = [System.Convert]::ToBase64String($binaryData, 0, $binaryData.Length)
[int] $position = 0
while($position -lt $base64Value.Length)
{
   [int] $chunkSize = 100
   if (($base64Value.Length - ($position + $chunkSize)) -lt 0)
   {
       $chunkSize = $base64Value.Length - $position
   }
$MIMEMessage.AppendLine($base64Value.Substring($position, $chunkSize))|Out-Null
$MIMEMessage.AppendLine()|Out-Null
$position += $chunkSize;
}
$MIMEMessage.AppendLine("--unique-boundary-1--") | Out-Null

[Byte[]] $BodyBytes = [System.Text.Encoding]::ASCII.GetBytes($MIMEMessage.ToString())
$ContentInfo = New-Object System.Security.Cryptography.Pkcs.ContentInfo (,$BodyBytes) 
$CMSRecipient = New-Object System.Security.Cryptography.Pkcs.CmsRecipient $ChosenCertificate 
$EnvelopedCMS = New-Object System.Security.Cryptography.Pkcs.EnvelopedCms $ContentInfo 
$EnvelopedCMS.Encrypt($CMSRecipient) 
[Byte[]] $EncryptedBytes = $EnvelopedCMS.Encode() 
$MemoryStream = New-Object System.IO.MemoryStream @(,$EncryptedBytes) 
$AlternateView = New-Object System.Net.Mail.AlternateView($MemoryStream, "application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m") 
$Message.AlternateViews.Add($AlternateView)
$MailClient.Send($Message)

如果沒有對電子郵件中的密碼進行加密,我不禁覺得您正試圖從電子郵件中獲得一定程度的安全性,而這並不是為它設計的。您相信將密碼放入電子郵件中,但不相信收件人是誰,並嘗試在 Outlook 中為單個電子郵件添加一定級別的驗證。這對我來說聽起來很有缺陷。

如果您仍然要設置網頁,為什麼不在網頁上完成所有操作,並在那裡完成使用者身份驗證?如果需要,僅將電子郵件用於 2FA 驗證層。

引用自:https://serverfault.com/questions/913732