使用 Oauth 的 Powershell Exchange EWS 脚本身份验证无法使用保存密码哈希文件
Powershell Exchange EWS script authentication using Oauth unable to use a save password hash file
通常对于预定的脚本,我将哈希文件保存到磁盘,以供脚本使用,如下所示:
$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)
如果 Body 中的密码元素以纯文本形式输入,则以下 Oath 令牌请求有效,但如果我使用变量 $Credential.Password 则无效。有没有办法让它工作,或者以其他方式保护密码?
以下令牌请求生成的错误:
错误:调用 RestMethod:{"error":"invalid_grant","error_description":"AADSTS50126: Error validating credentials due to invalid username or password..."error_uri":"login.microsoftonline.com/error?code=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
##########
=============================
根据 pip3r 的回答更新脚本,微软支持:
密码和机密以纯文本形式在线上传递,但不是
暴露在脚本中,并有一定程度的安全性保存为哈希
文件
调整为不将密码或机密保存到变量中
提高安全性,免受可以访问内存的攻击(MS
支持推荐)
选择为 Azure 注册应用程序使用证书而不是
一个 App Secret,以提高在线安全性
替代选项是使用“Azure Automation”,它允许
运行 来自 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"
所以...我将提供这个作为答案,因为我希望人们理解这是使用 Get-Credential 在文件中存储密码(即使作为密文字符串值)的问题的示例.
@mbromb,这将为您提供一种方法来测试您正在检索的值是否是正确的值:
在您的 $Credential 对象上(最后一行),运行:$Credential.GetNetworkCredential().Password
这将是您最初使用 Get-Credential 在提示中输入的任何内容的 PLAINTEXT 值。因此,您可以验证在最初获取它、将其写入文件、读回并将其转换为安全字符串对象后是否按预期工作。
尝试更直接地解决这个问题:如果我找到你的 'admin.pwd' 文件,从中生成明文是非常简单的。
警告:您可以通过使用 ConvertTo/From-SecureString cmdlet 上的 -Key 或 -SecureKey 属性为此加密过程提供受保护的密钥来保护此值。 Key 采用一个字节数组(最好是加密随机的,具有足够的熵来满足您的需要),SecureKey 接受一个字符串(密码)并根据您的密码生成字节数组。
注意事项:如果您已经在尝试将密码存储到文件中,那么保护存储密码的密码可能不是正确的答案...
通常对于预定的脚本,我将哈希文件保存到磁盘,以供脚本使用,如下所示:
$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)
如果 Body 中的密码元素以纯文本形式输入,则以下 Oath 令牌请求有效,但如果我使用变量 $Credential.Password 则无效。有没有办法让它工作,或者以其他方式保护密码?
以下令牌请求生成的错误:
错误:调用 RestMethod:{"error":"invalid_grant","error_description":"AADSTS50126: Error validating credentials due to invalid username or password..."error_uri":"login.microsoftonline.com/error?code=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
##########
=============================
根据 pip3r 的回答更新脚本,微软支持:
密码和机密以纯文本形式在线上传递,但不是 暴露在脚本中,并有一定程度的安全性保存为哈希 文件
调整为不将密码或机密保存到变量中 提高安全性,免受可以访问内存的攻击(MS 支持推荐)
选择为 Azure 注册应用程序使用证书而不是 一个 App Secret,以提高在线安全性
替代选项是使用“Azure Automation”,它允许 运行 来自 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"
所以...我将提供这个作为答案,因为我希望人们理解这是使用 Get-Credential 在文件中存储密码(即使作为密文字符串值)的问题的示例.
@mbromb,这将为您提供一种方法来测试您正在检索的值是否是正确的值:
在您的 $Credential 对象上(最后一行),运行:$Credential.GetNetworkCredential().Password
这将是您最初使用 Get-Credential 在提示中输入的任何内容的 PLAINTEXT 值。因此,您可以验证在最初获取它、将其写入文件、读回并将其转换为安全字符串对象后是否按预期工作。
尝试更直接地解决这个问题:如果我找到你的 'admin.pwd' 文件,从中生成明文是非常简单的。
警告:您可以通过使用 ConvertTo/From-SecureString cmdlet 上的 -Key 或 -SecureKey 属性为此加密过程提供受保护的密钥来保护此值。 Key 采用一个字节数组(最好是加密随机的,具有足够的熵来满足您的需要),SecureKey 接受一个字符串(密码)并根据您的密码生成字节数组。
注意事项:如果您已经在尝试将密码存储到文件中,那么保护存储密码的密码可能不是正确的答案...