网络安全。我是不是正确保护了我的 REST api? (node.js 快递)
Posted
技术标签:
【中文标题】网络安全。我是不是正确保护了我的 REST api? (node.js 快递)【英文标题】:Web security. Am I protecting my REST api properly? (node.js express)网络安全。我是否正确保护了我的 REST api? (node.js 快递) 【发布时间】:2018-06-25 03:58:55 【问题描述】:我有一个带有 REST 之类的 API 的 MEAN 堆栈应用程序。我有两种用户类型:用户和管理员。为了让用户登录并保持会话,我像这样使用 jsonwebtoken jwt(简化):
const jwt = require("jsonwebtoken");
//example user, normally compare pass, find user in db and return user
let user = username: user.username, userType: user.userType ;
const token = jwt.sign( data: user , secret,
expiresIn: 604800 // 1 week
);
为了保护我的特快路线,我这样做:
在这个例子中,它是一个“获取用户”路由,管理员可以获取任何给定用户的信息。 “普通”用户只被允许获取关于他/她自己的信息,为什么我将请求的用户名与从令牌解码的用户名进行比较。
let decodeToken = function (token)
let decoded;
try
decoded = jwt.verify(token, secret);
catch (e)
console.log(e);
return decoded;
// Get one user - admin full access, user self-access
router.get('/getUser/:username', (req, res, next) =>
let username = req.params.username;
if (req.headers.authorization)
let token = req.headers.authorization.replace(/^Bearer\s/, '');
decoded = decodeToken(token);
if (decoded.data.userType == 'admin')
//do something admin only
else if (decoded.data.username == username)
//do something user (self) only
else
res.json( success: false, msg: 'not authorized' );
else
res.json( success: false, msg: 'You are not logged in.' );
)
所以我的问题是,这有多安全?有人可以操纵会话令牌将用户名交换为其他人的用户名吗?甚至将用户类型从用户更改为管理员?
我的猜测是。只有当他们知道“秘密”,但这是否足够安全?秘密毕竟就像存储在代码中的纯文本密码一样。最佳做法是什么?
【问题讨论】:
你跑到let user = username: user.username, userType: user.userType ;
了吗? IIUC,这定义了一个变量user
,它最初是undefined
。然后是评估...
的时候了,这涉及访问user.username
。在 undefined
上查找 username
属性失败并出现 TypeError。
我不明白我是怎么遇到这个问题的,或者我不完全理解你的意思。正如我在代码中的注释所解释的,用户对象只是一个示例。通常会从数据库返回一个用户,如果不是,则会处理错误。
请忽略。您的示例代码令人困惑,但我想我理解您的意思。如果jwt.verify
失败并在decodeToken
中出现异常,则if (decoded.data.userType == 'admin')
中确实存在问题,因为decoded === undefined
。也许考虑将decoded
初始化为结构上有效的值,这意味着catch
块中没有权限。此外,decoded
可能应该在您的处理程序中使用 let
声明。
啊,是的。我想我明白你的意思。通常当 jwt.verify 失败时,它会生成一个响应,说“缓冲区错误,机密必须是字符串类型”......类似的东西。但是,然后它失败了,并且没有达到代码的“脆弱”部分,这是主要问题。不过,感谢您指出,我会尝试引发一些 jwt 错误并寻找解决方案。
【参考方案1】:
这是非常安全的,特别是如果通过 HTTPS 发送 - 那么攻击者将不知道您的请求负载是什么样的。
唯一真正的危险是确保您保持秘密的安全,不要保存在公共 git 存储库中,锁定对任何存储秘密的盒子的访问。使用编码的秘密。
还有其他方法可以强化您的服务器。考虑使用 npm 流行的 helmet 模块。
【讨论】:
谢谢,这正是我需要知道的。我是 ssl 加密的,所以我想这个应用程序对于我的目的来说已经足够好了。我以前用过头盔,但这次我只用了cors。如果以后遇到威胁,也许我应该考虑添加头盔中间件。【参考方案2】:如果您的数据包通过 HTTPS 发送,这是安全的。如果您想添加另一层安全性,您可以首先在iron 的帮助下加密用户详细信息,iron 使用“aes-256-cbc”进行加密,然后使用该加密文本并通过生成令牌JWT。这样,如果用户以某种方式访问您的令牌并访问JWT 的网站。他将无法识别此令牌中的内容。
再次强调,这只是增加了一层额外的安全性,从技术上讲,人们无法提取信息,因为这非常耗时,但为我们的应用程序增加了一些额外的安全性。
还要确保您的所有秘密(密钥)都是私密的。
【讨论】:
非常感谢您的建议!高度赞赏:) 随时:) 如果您需要任何帮助,请告诉我。【参考方案3】:回答您最初的问题“有人可以操纵会话令牌以将用户名交换为其他人的用户名吗?甚至将 userType 从用户更改为管理员?”
JWT 令牌从服务器端加密并以响应的形式发送到客户端。使用该令牌,需要牢记两点:
-
令牌使用只有服务器知道的私钥加密
令牌包含所谓的
signature
,用于验证 JWT 有效负载的内容(例如 userType
等)
关于第一点的更多信息,请参考以下answer。
为了更好地展示 JWT 令牌和签名,请查看以下 URL - https://jwt.io/
考虑到这一点,您必须确保:
您的密钥在任何时候都不会暴露给外部服务/客户端。理想情况下,该密钥甚至没有硬编码在您的代码库中(请问您是否希望我详细说明)。
您的端点没有任何逻辑缺陷。
从设计的角度来看,我更愿意将与管理空间相关的任何端点隔离到它们自己的端点中,但是快速浏览一下,您的代码似乎很好。 :-)
附带说明一下,如果您在 Web 应用程序安全方面没有太多经验,我建议您查看一些自动扫描程序,例如 Acunetix、Burp(混合)等。虽然无论如何都不完美,但它们非常有能力检测大量的行为漏洞(例如,恶意行为者通常会利用的漏洞)。
【讨论】:
请注意,jwt 令牌未加密,仅签名。内容对用户可见,只有其完整性(真实性)受到保护。【参考方案4】:秘密毕竟就像存储在代码中的纯文本密码。
没错。如果secret
没有保密,那么攻击者可以伪造用户对象并使用该秘密对其进行签名,而verify
将无法区分。
将秘密放入代码中可能会导致秘密泄露。它可能通过您的代码存储库泄漏,因为配置错误的服务器将 JS 源文件作为静态文件提供,或者因为攻击者找到了一种方法来利用 child_process
调用来回显服务器上的源文件。您的用户的安全不应依赖于没有人犯此类常见错误。
什么是最佳实践?
使用密钥管理系统 (KMS),而不是自行滚动或在代码中嵌入秘密。 Wikipedia 说
密钥管理系统 (KMS),也称为加密密钥管理系统 (CKMS),是一种用于为设备和应用程序生成、分发和管理加密密钥的集成方法。
通常,您如何执行此操作取决于您的主机。比如Google Cloud和AWS都提供密钥管理服务。
https://www.npmjs.com/browse/keyword/kms 可能会帮助您找到适合您的堆栈的东西。
【讨论】:
这确实是密钥管理问题的答案。然而,对于较小的项目,这通常是不可行的,这是非常不幸的,因为将秘密存储在 Web 服务器上是一个真正的风险。 @GaborLengyel,当您说“较小的项目”时,您指的是那些不在 gCloud 或 AWS 等容器中运行的项目吗? Kubernetes 可能是这些人的选择吗? 不幸的是,我对 Kubernetes 不够熟悉,但可能是的,这听起来是一个合理的想法!谢谢:)【参考方案5】:以上代码中的一些潜在漏洞:
变量 username
来自 url,但 usertype
是从路由器操作中的令牌断言的。例如,如果审计日志从 username
变量中获取用户 ID,则它可能会损坏,因为这不是真实的并且可以是用户发送的任何内容。
重播是个问题。由于令牌有效期为一周,因此在令牌过期之前无法撤销管理员权限。 (恶意用户可以重放之前的管理员令牌。)
同样,在令牌过期之前,您不能终止(强制注销)任何会话。这是此类无状态设计中的常见问题。
其他人指出的令牌解码后的空引用。在 node.js 中,这更像是一个弱点而不是一个漏洞,我认为它是不可利用的。
服务器上的秘密非常有价值,可以用来冒充任何用户。在安全性要求高的系统中很难保护这样的秘密。
因此,与另一个答案相反,这远非“非常安全”,但对于许多目的来说是相当安全的。
【讨论】:
第一点。我不这么认为,或者我错过了一些东西。是的,“任何人”可以在 url 参数中发送他/她想要的任何用户名,但请注意,它与从令牌解码的用户名进行比较。即用户将永远无法访问隐藏在令牌中的任何其他用户。忘记用户ID,它们不用于任何比较。 ;) 我知道会话到期,这实际上只是出于开发原因,将在发布时缩短为 1 天。您的最后一点,是的,这是我发布此 q 时的担忧之一。我希望多保护一点。谢谢你的回复以上是关于网络安全。我是不是正确保护了我的 REST api? (node.js 快递)的主要内容,如果未能解决你的问题,请参考以下文章
使用 OAuth2.0 或 Azure Active Directory 保护 REST API
什么是 OAuth,它如何保护 REST API 调用? [关闭]