我正在建立一个节点/快速后端。我想创建一个只能与我的reactjs前端(私有API)一起使用的API。
想象一下,如果这是一个电子商务网站,我的用户将浏览产品,然后选择购买什么,在订购时他们可能会或可能不会登录。
确保我的API仅适用于reactjs前端的最佳做法是什么?
当用户决定登录或是否仍为访客时会发生什么?
答案 0 :(得分:3)
应用CORS - 服务器指定允许请求您的API的域。
它是如何运作的?
尊重CORS(浏览器)的客户将会(或不会被拒绝)能够连接。如果客户端忽略CORS(REST客户端,CLI工具......),它将能够连接,无论是什么......
仍然需要签名请求(授权)
答案 1 :(得分:1)
这个用例很有意思,我觉得很多电子商务网站都存在问题。我正在研究的product实际上与试图在移动领域处理这种事情的公司进行了一些对话。用户登录可用于告诉您谁正在使用API,但如果您不想强迫用户拥有用户名/登录信息,则必须搜索备用解决方案。您似乎想要的是一种识别试图使用您的API的软件的方法。
通常有几种简单的方法可以解决这个问题:
嵌入式密钥
您可以向应用添加密钥,并要求对API的任何访问都使用密钥标识自己。人们会告诉你不要这样做,因为提取密钥真的很容易。这是事实,但是在所有安全性的情况下,都需要进行成本/收益分析,以评估您希望在保护API方面投入多少工作。 javascript的问题在于,混淆或隐藏秘密并不容易,因为所有源代码都在那里。
如果您正在考虑一个环境,您可以选择其他语言选项,那么您可以采取更多措施来混淆应用中的秘密(例如在Android中使用NDK)。但Javascript很难。
使用API密钥要记住的重要一点是,您不应该以明文形式传输它。这样偷走真的很容易。相反,您可以使用密钥对API流量进行签名,以便服务器可以验证请求来自具有密钥的内容并知道如何对其进行签名。
速率限制
虽然实际上并不是问题的解决方案,但根据您要实现的目标,这是一个选项。如果您担心来自其他应用程序的大量请求,您可以将限制速率限制在高于真实应用程序的水平,如果有太多请求,您可以通过IP地址进一步阻止或限制速率。
答案 2 :(得分:0)
所以,这可能是一个稍微冗长的答案 - 但你发布了一个相当有趣和重要的问题。
作为一个花费我大部分时间在Node和Python中编写安全库来处理这类事情的人,我想我会跳进去。
您要用于保护React应用和后端API的协议是OAuth2密码授予流程。它在理论上的运作方式非常简单。
在您的React应用程序中,您收集用户的用户名/密码(如果您的应用程序结构如此,也可以是电子邮件/密码)。
然后向您的后端API发送一个POST请求,如下所示:
POST api.myapp.com/oauth/token
grant_type=password&username=USERNAME&password=PASSWORD
确保在发布到服务器时使用application/x-www-form-urlencoded
内容类型。
然后,您的服务器将接收此请求,通过OAuth2库运行该请求,并生成两个令牌:以及访问和刷新令牌。
一旦你在服务器端API上生成了令牌,你就会将这些令牌存储在一个cookie中,然后由用户的浏览器存储。
从这一点开始:一切都应该是自动的。当您的React服务器向您的后端发出API请求时,浏览器将通过包含这两个令牌的cookie自动识别用户。
您需要为服务器端使用OAuth2库,因为这将处理以下内容:
还有很多东西,但这是基本的,高水平的想法。
您会注意到:此处不涉及API密钥。当您使用不受信任的环境(例如:移动应用程序或客户端javascript应用程序)时,存储永久API令牌完全不安全 - 原因是可以从源代码中轻松提取它们或者javascript。
使用上面提到的流程更加安全,因为您可以获得很多保护:
无论如何:希望这有帮助!
而且,如果您正在寻找一些工具,任何oauth库(服务器端)都应该帮助您解决这些问题。如果您正在寻找可以为您执行此操作的服务,您可能需要查看我所使用的产品(Stormpath)。这是一项付费服务,但代表您处理了很多这种复杂性。
答案 3 :(得分:0)
从今天开始,任何用户都可以通过检查浏览器控制台中的“网络”选项卡来查看正在传递给后端的内容。确保api安全的唯一方法是使用JWT或类似工具通过用户身份验证。如果您的应用程序是向来宾用户开放的,那么cors并不能真正起到帮助作用,因为所有用户要做的就是通过curl或postman向您的api发出与他们在浏览器控制台中看到的请求相同的请求。
答案 4 :(得分:0)
我从上述solution by @ThePragmatist那里获得了帮助。
我在React网站上有一些基于环境的配置,例如后端API基本URL(例如staging-api.test.com,dev-api.test.com),当前域名(例如staging.test) .com,dev.test.com等),因此我使用变量创建了一个令牌,该令牌将在每个公共请求上发送(从公共请求中我指的是不需要授权的请求)。所以我遵循的过程是:
在客户端:
user-agent/IP/something else from the header
+ request timestamp
+ _
+ random 6 digit string
创建字符串backend_api
+ domain
+ another config
之类的几种组合)作为私钥和在上述步骤中生成的字符串来创建JWT令牌token
的自定义标头中在服务器端进行验证:
Redis
实现的任何公共API请求,以阻止用户对新请求使用相同的令牌。token
中收到的JWT令牌。如果JWT可以验证,请继续进行处理,否则返回403
timestamp
。如果时间戳记为2分钟或更早,请使用524
(或根据您的需要的其他方式)拒绝请求,否则请继续token
标头值的redis键。如果确实如此,则意味着先前在请求中使用了相同的标头,然后只需使用403
拒绝该请求,否则继续进行token
中的Redis
标头保存在expire time
中,时间为2分钟+ 10秒(仅占用10秒就可以缓冲一次)这样,由于我们使用多个配置作为私钥来对标头进行签名,因此所有公共请求都将发送一个令牌,垃圾邮件发送者/黑客很难猜测到该令牌。另外,他们将无法在另一个请求中使用相同的header
。只有客户端应用程序才能生成令牌,因为我们遵循了诸如标头,时间戳,最后的随机字符串(只是造成一些混乱)之类的多种内容。
我希望它能解决某人的疑问。
答案 5 :(得分:-1)
这样做的一种方法在向服务器发送任何AJAX请求时,发送一个包含某些密钥的标头,如apiKey:"某些密钥"。在服务器中,只要您收到它并验证您的反应应用程序正在服务的域。如果不是,你不需要回应。像
这样的东西app.get('/route', function(req, res) {
if(req.headers.apiKey == "some key) // respond with success
// respond with 401 Forbidden
});
因此任何命中服务器的请求都应该有apiKey以使我工作。