【问题标题】:Powershell Exchange EWS script authentication using Oauth unable to use a save password hash file使用 Oauth 的 Powershell Exchange EWS 脚本身份验证无法使用保存密码哈希文件
【发布时间】:2020-07-04 06:18:46
【问题描述】:

通常对于计划脚本,我将哈希文件保存到磁盘,以便脚本使用如下凭据:

$Credential = Get-Credential Admin@domain.com 
$Credential.Password | ConvertFrom-SecureString | Set-Content "C:\admin.pwd" $Username = "Admin@domain.com" 
$Password = Get-Content "C:\admin.pwd" -ErrorAction stop | ConvertTo-SecureString
$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password) 

如果正文中的密码元素以纯文本形式输入,则以下 Oath 令牌请求有效,但如果我使用变量 $Credential.Password 则无效。有没有办法让它工作,或者以其他方式保护密码?

以下令牌请求产生的错误:

错误:Invoke-RestMethod : {"error":"invalid_grant","error_description":"AADSTS50126: 由于用户名或密码无效,验证凭据时出错..."error_uri":"login.microsoftonline.com/error?代码=50126"}

## Request an access token

# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'AppIdHere'
$AppSecret = 'AppSecretHere'
$Scope = "https://outlook.office365.com/.default"
$TenantName = "Domain.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Create body
$Body = @{
    client_id = $AppId
    client_secret = $AppSecret
    scope = $Scope
    grant_type = 'password'
    username = 'Admin@domain.com'
    password = $Credential.Password
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'

    # Create string by joining bodylist with '&'
    Body = $Body
    Uri = $Url
}

# Request the token for user!
$Request = Invoke-RestMethod @PostSplat

$Request.access_token

##########

============================

根据 thepip3r 的回答和 Microsoft 支持更新了脚本

密码和秘密在网络上以纯文本形式传递,但不是 暴露在脚本中,并有一定程度的安全性保存为哈希 文件

调整为不将密码或秘密保存到变量中 提高安全性免受可以访问内存的攻击(MS 推荐支持)

为 Azure 注册应用程序使用证书而不是使用证书的选项 一个 App Secret,以提高网络的安全性

另一种选择是使用“Azure 自动化”,它允许 从 O365 中运行脚本,这应该更安全。 另一种可能的替代方案可能是 Azure Functions。

# One time AppID\Secret hash save to file:
## $AppCredential = Get-Credential 'AppIdHere'
## $AppCredential.Password | ConvertFrom-SecureString | Set-Content "C:\App.pwd" 

# One time Admin hash save to file:
## $Credential = Get-Credential admin@domain.com
## $Credential.Password | ConvertFrom-SecureString | Set-Content "C:\admin.pwd" 

$AppId = 'AppIdHere'
$AppS = Get-Content "C:\App.pwd"  | ConvertTo-SecureString
$AppCredential = New-Object System.Management.Automation.PSCredential($AppId,$AppS)

$Username = "admin@domain.com"
$Password = Get-Content "C:\admin.pwd" | ConvertTo-SecureString
$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password)        

### Request an access token ###

$Scope = "https://outlook.office365.com/.default"
$TenantName = "usablelife.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

# Request the token!
$Request = Invoke-RestMethod -Body @{
    client_id = $AppId
    client_secret = $AppCredential.GetNetworkCredential().Password
    scope = $Scope
    grant_type = 'password'
    username = $Username 
    password = $Credential.GetNetworkCredential().Password
} `
-ContentType 'application/x-www-form-urlencoded' `
-Method 'POST' `
-Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

【问题讨论】:

    标签: powershell authentication exchange-server exchangewebservices


    【解决方案1】:

    所以...我将提供此作为答案,因为我希望人们理解这是一个示例,即使用 Get-Credential 将密码存储在文件中(甚至作为密文字符串值)的问题。

    @mbromb,这将为您提供一种方法来测试您检索的值是否是正确的值:

    在您的 $Credential 对象(最后一行)上,运行:$Credential.GetNetworkCredential().Password

    这将是您最初使用 Get-Credential 在提示中输入的任何内容的 PLAINTEXT 值。因此,您可以验证在最初获取它之后,将其写入文件、读回文件并将其转换为安全字符串对象是否按预期工作。

    尝试更直接地解决这个问题:如果我找到您的“admin.pwd”文件,从中生成明文非常简单。

    警告:您可以通过使用 ConvertTo/From-SecureString cmdlet 上的 -Key 或 -SecureKey 属性为此加密过程提供受保护的密钥来保护此值。 Key 接受一个字节数组(最好是加密随机的,具有足够的熵来满足您的需要),SecureKey 接受一个字符串(密码)并根据您的密码生成字节数组。

    Caveat-to-the-caveat:如果您已经尝试将密码存储到文件中,那么保护存储密码的密码可能不是正确的答案...

    【讨论】:

    • 谢谢!我已经用调整后的脚本更新了问题。似乎它会运作良好。我设置了$Pass = $Credential.GetNetworkCredential().Password,并将其作为密码发送。它需要纯文本密码而不是安全字符串,这是有道理的。我对 AppID\Secret 执行相同的操作,因此用户密码或 App Secret 都不会在脚本中以纯文本形式公开。我还发现,除非我使用创建它的用户,否则我无法对 PWD 文件执行任何操作,这就是将散列 PWD 文件用于计划脚本时的工作方式。
    • 现在我想了想,脚本现在以纯文本形式通过网络传递管理员密码。这似乎不安全,但我无法使用安全字符串。
    • 我发现了这个,link:“因为客户端应用程序必须收集用户的密码并将其发送到授权服务器,所以不建议再使用这个授权。” link:“不得使用资源所有者密码凭证授权”所以看来我又回到了原点。
    • 这段代码 sn-p 有帮助吗?查看底部的代码,他们使用不同的凭据对象:devblogs.microsoft.com/scripting/…
    • 这描述了如何使用 EWS 处理邮箱,这是我的脚本所做的。我需要做的是更改脚本的身份验证方式以完成这项工作。目前,我使用正在停用的基本身份验证,因此有必要切换到 Oauth,这就是为什么我在这里询问安全获取令牌的原因。我已经用 MS 打开了一个案例,adn 会发布它的结果。谢谢
    猜你喜欢
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 2015-12-17
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 2017-06-05
    • 1970-01-01
    相关资源
    最近更新 更多