如何解决构建使用 OAUTH
我正在构建一个小型测试 Slack 应用程序,但不清楚身份验证所需的架构。这将是一个存在于 Heroku 上的 NodeJS 应用程序。
当用户使用 /slash
命令时,它将调用将查询外部 CRM 系统并返回数据的逻辑。为了对这个外部系统进行身份验证,它需要通过 OAUTH 流发送用户,以便对数据的访问由调用用户的权限控制。
我的困惑是如何处理或保留这些身份验证令牌/刷新令牌,这些令牌是我们在此过程中从用户身份验证中获得的。
示例步骤:
- 运行
/user bob@gmail.com
- 检查用户是否已在此外部系统上授权
- 如果没有,请引导用户完成外部系统 oauth 流程
- 身份验证后,我们拥有可用于以该用户身份调用外部系统 API 的令牌。
- 进行标注并返回数据
当他们运行命令以查看我们是否已经拥有它时,我将如何持久化或检查松弛用户身份验证/刷新令牌?如果令牌已经存在,我就不需要再次通过 OAUTH 流发送它们。
我对方法的看法:
似乎需要某种类型的数据存储,其中包含松弛用户 ID、身份验证令牌和刷新令牌。当用户调用命令时,我们会检查该用户是否在表中,如果是,我们将使用他们的令牌进行 API 调用。
如果它们不存在,我们然后通过 OAUTH 流发送它们,以便我们可以存储它们。
最后的想法:
就安全性而言,拥有一张令牌表是正确的方法吗?如果有人要获得该令牌,这几乎就像存储纯文本密码一样。
解决方法
您的方法是正确的,docs in slack API 指出 this article 描述了您的用例,其中第三方是 Salesforce CRM。
就安全性而言,拥有一张令牌表是正确的方法吗? ...
是的,附加程序可能会窃取您的数据库数据。 为避免这种情况,您可以将令牌存储为加密字符串。 通过这种方式,恶意用户应该:
- 从数据库中窃取数据
- 窃取您的源代码以了解您使用什么类型的算法来加密令牌及其背后的逻辑
该方法是传播所有信息以获得跨系统的清晰令牌假设 一个或多个系统可能会受到攻击,而不是每个人!
有没有更好的方法来处理这个问题,或者这是一种常见的方法吗?
通常使用 AES-256,详细信息为 aes-256-gcm
或 aes-256-cbc
。有一些thread off
在性能和用例中,您必须处理以偏爱其中一个。
Node.js 支持两者,示例逻辑可能是:
const crypto = require('crypto')
const algorithm = 'aes-256-gcm'
const authTagByteLen = 16
const ivByteLen = 64
const keyByteLen = 32
const saltByteLen = 32
const oauthToken = 'messagetext'
const slackUserId = 'useThisAsPassword'
const salt = crypto.randomBytes(saltByteLen)
const key = crypto.scryptSync(
Buffer.from(slackUserId,'base64').toString('base64'),Buffer.from(salt,keyByteLen)
const iv = crypto.randomBytes(ivByteLen)
const cipher = crypto.createCipheriv(algorithm,key,iv,{ authTagLength: authTagByteLen })
let encryptedMessage = cipher.update(oauthToken)
encryptedMessage = Buffer.concat([encryptedMessage,cipher.final()])
const storeInDb = Buffer.concat([iv,encryptedMessage,cipher.getAuthTag()]).toString('base64')
/***
*
*/
const storeInDbBuffer = Buffer.from(storeInDb,'base64')
const authTag = storeInDbBuffer.slice(-authTagByteLen)
const iv2 = storeInDbBuffer.slice(0,ivByteLen)
const toDencryptMessage = storeInDbBuffer.slice(ivByteLen,-authTagByteLen)
const decipher = crypto.createDecipheriv(algorithm,iv2,{ authTagLength: authTagByteLen })
decipher.setAuthTag(authTag)
const messagetext = decipher.update(toDencryptMessage)
decipher.final()
const clearText = messagetext.toString()
console.log({
oauthToken,storeInDb,clearText
})
注意:
- SALT 逻辑将在每次运行时生成一个新的“storeInDb”字符串,而不会影响未来的读取
- 您可以使用 slack-user-id 作为密码,因此附加程序也应该知道此信息
- 您也必须存储盐或编写一个算法来从用户 ID 生成它,例如
- salt 可能存储在(redis)缓存或其他服务(如 S3)中,因此附加程序应该打破其他系统来解析令牌!
my module 提取的 GCM 示例 您可能会发现 CBC example here
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。