powershell - 使用 Oauth 的 Powershell Exchange EWS 脚本身份验证无法使用保存密码哈希文件
问题描述
通常对于预定的脚本,我将哈希文件保存到磁盘以供脚本使用,如下所示:
$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?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
##########
============================
根据 thepip3r 的回答和 Microsoft 支持更新了脚本:
密码和秘密在网络上以纯文本形式传递,但不会在脚本中公开,并具有一定程度的安全性,保存为哈希文件
调整为不将密码或秘密保存到变量中,以提高安全性,免受可以访问内存的攻击(推荐 MS 支持)
为 Azure 注册应用程序使用证书而不是应用程序密钥的选项,以提高网络安全性
另一种选择是使用“ 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"
解决方案
所以......我将提供这个作为答案,因为我希望人们理解这是一个示例,即使用 Get-Credential 将密码存储在文件中(甚至作为密文字符串值)的问题。
@mbromb,这将为您提供一种方法来测试您检索的值是否是正确的值:
在您的 $Credential 对象(最后一行)上,运行: $Credential.GetNetworkCredential().Password
这将是您最初使用 Get-Credential 在提示中输入的任何内容的PLAINTEXT值。因此,您可以验证在最初获取它之后是否将其写入文件、读回文件并将其转换为安全字符串对象是否按预期工作。
尝试更直接地解决这个问题:如果我找到您的“admin.pwd”文件,从中生成明文非常简单。
警告:您可以通过使用 ConvertTo/From-SecureString cmdlet 上的 -Key 或 -SecureKey 属性为此加密过程提供受保护的密钥来保护此值。Key 接受一个字节数组(最好是加密随机的,具有足够的熵来满足您的需要),SecureKey 接受一个字符串(密码)并根据您的密码生成字节数组。
注意事项:如果您已经尝试将密码存储到文件中,那么保护存储密码的密码可能不是正确的答案......
推荐阅读
- typescript - Typescript 中的递归类型映射
- sql - VBA SQL Access 数据库查询日期语句
- c++ - Qgraphics项目变慢
- delphi - 设计了一个电子邮件系统。给出一个不熟悉的异常
- snowflake-cloud-data-platform - 在 Snowflake SQL 中解析 JSON 数组键/值
- android - 查看某个 Fragment 时隐藏 AppBarLayout
- python - 如何更改 pygame 窗口顶部栏的颜色?
- node.js - Nodemon -e 不使用给定的扩展触发
- python - KivyMD 如何更改 MDToolbar 标题大小和字体?
- php - pdftk 未在 php 中执行