保护 Node.js 中的 API 路由

Posted

技术标签:

【中文标题】保护 Node.js 中的 API 路由【英文标题】:Protect API routes in Node.js 【发布时间】:2018-03-31 00:59:55 【问题描述】:

我的 Node.js API 中有一些路由将数据从 MongoDB 数据库发送到 Angular 4 前端。

例子:

Node.js 路由:

router.get('/api/articles', (req, res) => 
    Article.find(, (err, articles) => 
        if(err) return res.status(500).send("Something went wrong");
        res.status(200).send(articles);
    );
);

Angular 4 服务功能:

getArticles() 
    return this.http.get('http://localhost:3000/api/articles')
    .map(res => res.json()).subscribe(res => this.articles = res);

问题是,如何保护我的 Node.js API 路由免受浏览器访问?当我去http://localhost:3000/api/articles时,我可以看到我所有的json格式的文章。

【问题讨论】:

你真的不能。如果您要公开一个 API 以供 Angular 使用,那么任何 Web 代理也可以调用该 API。您可以在您的网站上要求一个登录帐户,您的服务器可以在 API 响应之前验证该帐户,但这就是您可以做的事情。可以设置各种障碍,使其更难从您的 Angular 代码外部访问,但与坚定的黑客相比,没有一个是安全的。 @jfriend00 谢谢,非常感谢您的 cmets。我的目标只是防止通过浏览器直接访问公共 API 路由。我在需要用户身份验证的地方使用令牌。 【参考方案1】:

这不是安全措施,只是过滤请求的一种方式。为了安全,请使用 JWT 或类似的其他机制。

如果 Angular 应用程序由您控制,则发送一个特殊的标头,例如 X-Requested-With:XMLHttpRequest(chrome 默认为 AJAX 调用发送它)并在响应之前检查此标头的存在。

如果您真的很想将端点暴露给特殊情况,请使用唯一标头 X-Request-App: MyNgApp 并对其进行过滤。

【讨论】:

这是一种防止在浏览器中键入 URL 的简洁方法。没有做任何事情来阻止黑客使用 API(你基本上做不到)。 绝对不是安全措施。这只是一个过滤器。 我决定使用这个解决方案来处理公共内容。在需要用户身份验证的地方,我使用令牌作为安全措施。【参考方案2】:

除非您愿意实施某种身份验证,否则您不能真正做到——即您的 Angular 用户将需要登录 api。

可以让它不那么方便。例如,简单地将您的路由切换为接受POST 请求而不是GET 请求将阻止浏览器轻易看到它。它仍然会在开发工具或 curl 中可见。

或者,您可以使用您在 express 处理程序中查找的 angular 请求设置一个标头,但这似乎只是为了安全的外观而做的很多工作。

【讨论】:

【参考方案3】:

最好的方法是实现一个认证令牌系统。您可以从静态令牌开始(稍后您可以通过授权实现动态令牌)。

Token 只是一个字符串,用于确保请求经过身份验证。

Node.js 路由:

router.get('/api/articles', (req, res) => 
    let token = url.parse(req.url,true).query.token;   //Parse GET param from URL
    if("mytoken" == token)         // Validate Token
       Article.find(, (err, articles) => 
        if(err) return res.status(500).send("Something went wrong");
        res.status(200).send(articles);
       );
    else 
       res.status(401).send("Error:Invalid Token"); //Send Error message
    

);

Angular 4 服务功能:

getArticles() 
    return this.http.get('http://localhost:3000/api/articles?token=mytoken') // Add token when making call
    .map(res => res.json()).subscribe(res => this.articles = res);

【讨论】:

@mikebrsv - 值得理解的是,任何可以从浏览器 javascript 中完成的事情(例如此处建议的内容)都可以由任何黑客完成,因此这只是一个障碍,而不是实际的预防措施。而且,这甚至不是防止用户在浏览器中输入 URL 的最简单方法——这可以通过将 API 更改为仅使用 POST 而不是 GET 来完成(这不符合 REST,但可以正常工作,因为所有来自 URL 栏的浏览器请求是 GET)。【参考方案4】:

使用 Express,您可以使用路由处理程序来允许或拒绝访问您的端点。此方法由 Passport 身份验证中间件使用(顺便说一下,您可以使用它)。

function isAccessGranted (req, res, next) 
  // Here your authorization logic (jwt, OAuth, custom connection logic...)
  if (!isGranted) return res.status(401).end()
  next()


router.get('/api/articles', isAccessGranted, (req, res) => 
  //...
)

或者让它对你的所有路线更通用:

app.use('*', isAccessGranted)

【讨论】:

以上是关于保护 Node.js 中的 API 路由的主要内容,如果未能解决你的问题,请参考以下文章

如何将 jwt 令牌发送到 node.js 中的受保护路由

httpOnly cookie 中的 JWT - AuthGuard 和受保护的路由(Node.js、Angular)

如何在 node.js 中设置受保护的路由?与我拥有的 userRoutes.js 相同

保护 Node.js RESTful API

无法在 Node JS 中使用 JWT 访问受保护的路由

Node.js API 受 Keycloak 保护,访问类型为“仅承载”