我正在编写一个 PowerShell 脚本来发送一封包含密码的安全电子邮件。我一直在研究好的实现方法,但找不到合适的方法。
场景如下:一个人请求密码,脚本会自动生成密码并发送到此人邮箱,此人使用Outlook打开邮箱。
我的愿望是强制使用其 AD 凭证的人打开电子邮件,但要做到这一点,运行此脚本的帐户需要拥有此人的证书。因此,这似乎是不可能的。
我的第二个想法是创建一个网页,密码请求者可以在其中解密通过电子邮件收到的密码。该网页需要单点登录和其他技巧来保护想要登录的经过身份验证的用户。
如果您有更好的想法,可以帮我解决吗?
答案1
除了加密电子邮件中的密码外,我忍不住觉得你试图从电子邮件中获得某种程度的安全,而这并非电子邮件设计所应具备的。你相信在电子邮件中输入密码,但不相信收件人是谁,并试图在 Outlook 中为单个电子邮件添加一定程度的验证。这听起来很不合理。
如果你无论如何都要设置一个网页,为什么不在网页上完成所有操作,并在那里完成用户身份验证?如果需要,请仅将电子邮件用于 2FA 验证层。
答案2
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 = "[email protected]"
$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)