如何保护REST API调用?


91

我正在开发一个宁静的Web应用程序,该应用程序在后端使用了一些流行的Web框架,例如(rails,sinatra,flask,express.js)。理想情况下,我想使用Backbone.js开发客户端。如何仅让我的javascript客户端与这些API调用进行交互?我不希望这些API调用是公开的,而不是通过curl浏览器上的链接输入或仅通过输入链接即可调用。


您的所有API调用是否都需要在提供页面时传递给客户端的令牌?
hajpoj 2012年


- :亚马逊AWS的JavaScript SDK使用预先签订目标URL docs.aws.amazon.com/AmazonS3/latest/dev/...
rjha94

Answers:


90

作为首要原则,如果您的JS客户端使用了您的API,则必须假定它是公共的:一个简单的JS调试器会将攻击者置于一个位置,在该位置,攻击者可以从攻击者发送逐字节的相同请求。他选择的工具。

就是说,如果我正确地阅读了您的问题,那不是,您要避免的是:您真正不希望发生的事情是,在不涉及JS客户端的情况下(定期)消耗了API。以下是一些有关如何强制执行(至少鼓励使用客户端)的想法:

  • 我确定,您的API具有某种身份验证字段(例如,在客户端上计算的哈希)。如果不是,请查看This SO问题。确保您使用基于会话(自动编码的Aot)分配给JS客户端的盐(甚至API密钥)。这样,未经授权使用您的API的消费者将被迫进行更多工作。

  • 加载JS客户端时,请记住一些HTTP标头(想到的是用户代理)和IP地址,如果它们发生更改,请重新进行身份验证,并为通常的可疑对象使用黑名单。这迫使攻击者再次更加彻底地完成作业。

  • 在服务器端,请记住最后几个API调用,并在允许另一个API调用之前,检查业务逻辑是否现在允许新的API调用:这使攻击者无法将其许多会话集中到与服务器的一个会话中:结合其他措施,这将使施虐者容易被发现。

我可能没有以必要的明确性来这么说:我认为不可能使滥用者完全不可能使用您的服务,但是您可以使它变得如此艰难,这不值得麻烦。


这对您很有帮助,但是如果我想从后端api向另一个api应用(例如单独的服务器)进行身份验证,以简化我的问题,我希望后端aka node.js将获取请求发送到另一个后端,我的终端服务器是我自己的,出于某些原因这是必需的,但是我想保护api调用,因为它可以访问敏感数据,并且我不能使用sesions或jwt,因为我无法将它们实际存储在浏览器中。
金字塔

@Thepyramid没关系,API调用在服务器端执行什么操作,尤其是如果服务器端执行另一个第二级API调用。重要的部分是不要将服务器视为代理,而应将其视为应用程序。
Eugen Rieck

您能解释一下如何使应用程序不作为代理吗
金字塔

1
我的意思是:要获得可观的安全性,您需要使用Web应用程序具有的所有工具:会话,身份验证数据库,业务逻辑。如果不这样做,仅将您的服务器视为将请求传递到另一台服务器的一种方式,则您只是将其用作该另一台服务器的代理,并且受到其他服务器提供的任何安全性的限制。
Eugen Rieck

1
@PirateApp攻击者可以轻松忽略CSRF标头。仅当最终设备是未修补的浏览器时,它们才起作用
Eugen Rieck

12

您应该实现某种身份验证系统。处理此问题的一种好方法是定义一些预期的标头变量。例如,您可以进行auth / login API调用,以返回会话令牌。随后对API的调用将期望在HTTP标头变量中设置会话令牌,并使用“ your-api-token”之类的特定名称。

或者,许多系统使用某种api帐户系统创建预期的访问令牌或密钥(例如youtube,facebook或twitter)。在这种情况下,您的客户将不得不以某种方式将其存储在客户中。

然后,只需将会话检查添加到REST框架中并引发异常即可。如果可能的话,状态码(要保持安静)将是401错误。


8
尽管没有什么可以阻止它们查看标头并再现它们的。
cdmckay

1
@cdmckay-令牌必须与会话中存储的令牌匹配。如果标头来自不同的会话,则仅复制标头将导致“未经授权”响应。
Andrei Volgin 2015年

3
他们仍然可以使用相同的会话并在将请求发送到API之前更改请求……甚至在运行时使用控制台生成具有匹配标头/字段的调用,仅修改所需的部分……
Potter Rafed

2
@PotterRafed:如果用户访问他或她自己的有效会话,则使用应用程序调用该会话,而不对其进行攻击。认证的目的是防止访问其他用户的会话/数据。
Andrei Volgin

@AndreiVolgin是的,这很公平,但这仍然是一个漏洞
Potter Rafed

9

现在有一个开放标准,称为“ JSON Web令牌”,

参见https://jwt.io/https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web令牌(JWT)是基于JSON的开放标准(RFC 7519),用于创建声明某些声明的令牌。例如,服务器可以生成一个令牌,该令牌具有“以管理员身份登录”的声明,并将其提供给客户端。然后,客户端可以使用该令牌来证明他们以管理员身份登录。令牌由服务器的密钥签名,因此服务器能够验证令牌是合法的。令牌被设计为紧凑的,URL安全的,并且尤其在Web浏览器单点登录(SSO)上下文中可用。JWT声明通常可用于在身份提供商和服务提供商之间传递经过身份验证的用户的身份,或者用于业务流程所需的任何其他类型的声明。[1] [2] 令牌也可以进行身份​​验证和加密。[3] [4]


什么会阻止用户复制其令牌并在其他任何响应中使用它?
乌拉德·卡萨赫

1
@UladKasach说实话我从来没有真正深入到他们,但据我所知他们expireable,独特的用户,并通过SSL(这你当然修炼)加密的,这是背后的OAuth完全相同的想法AFAIK
bbozo

3

对不起,@ MarkAmery和Eugene,但这是不正确的。

您可以将在浏览器中运行的js + html(客户端)应用设置为排除未经授权直接调用API的方法,如下所示:

  1. 第一步:设置API以要求身份验证。该客户端必须通过服务器(或其他安全服务器)首先验证自身例如要求人类用户提供正确的密码。

身份验证之前,不接受对API的调用。

在身份验证期间,将返回“令牌”。

验证后,将仅接受带有验证“令牌”的API调用。

当然,在此阶段,只有拥有密码的授权用户才能访问API,尽管如果他们是调试应用程序的程序员,则他们可以出于测试目的直接访问它。

  1. 第二步:现在设置一个额外的安全性API,在最初从服务器请求客户端js + html应用程序后的短时间内将调用该API。此“回调”将告诉服务器客户端已成功下载。仅当最近成功请求客户端时,才限制REST API调用起作用。

现在,为了使用您的API,他们必须首先下载客户端并在浏览器中实际运行它。只有在成功接收到回调并在短时间内输入用户之后,API才会接受调用。

因此,您不必担心这可能是没有凭据的未经授权的用户。

(问题的标题为“如何保护REST API调用”,从您的大部分观点出发,这是您的主要担忧,而不是字面意义上的如何调用您的API的问题,而是由WHOM正确的吗? )


5
第二点没有道理。如果攻击者需要加载您的应用程序,他会做(您的回调是可见的)。然后进攻。
Andrei Volgin 2015年

第2点是第1点的补充。攻击者仍然需要身份验证。要点2仅增加了需要实际下载html应用才能获得授权的需求。因此,无法直接调用不带应用程序的API(大概只有在身份验证之后才能访问和下载)。这是这个问题所要求的。
pashute

您可以只允许来自您域的请求。
Andrei Volgin 2015年

这仅将调用限制在域内,因此现在javascript浏览器应用程序用户必须在域内(可能不是人们想要的东西),并且这些用户仍可以直接通过curl调用API。
pashute

2
您似乎忽略了的是,无论您要求用户的浏览器做什么,它都可以被攻击者复制-要使浏览器做到这一点,它必须可读。
Eugen Rieck

1
  1. 客户端第一次加载您的index.html(或其他backbone.js)内容时,在服务器上设置SESSION变量

  2. 在每个API调用的服务器端检查此var。

PS这不是一个“安全性”解决方案!!!这仅仅是为了减轻服务器上的负载,这样人们就不会滥用它或从其他网站和应用程序“热链接”您的API。


0

这是我的工作:

  1. 使用带有诸如X-APITOKEN之类的调用的HTTP标头来保护API:

  2. 在PHP中使用会话变量。有一个登录系统,并将用户令牌保存在会话变量中。

  3. 用Ajax将JS代码调用到PHP,并使用带有curl的session变量来调用API。这样,如果未设置会话变量,它将不会调用,并且PHP代码包含对API的访问令牌。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.