如何确保我的REST API仅响应受信任客户端(对于我自己的移动应用程序)生成的请求?我想防止来自其他来源的不必要的请求。我不希望用户填写序列号或其他任何东西,它应该在安装后在后台进行,并且不需要任何用户交互。

据我所知,HTTPS仅用于验证与之通信的服务器是谁。我当然要使用HTTPS加密数据。

有没有办法做到这一点?

更新:
用户可以执行只读操作,这些操作不需要用户登录,但是他们还可以执行写操作,但要求用户登录(通过访问令牌认证)中。在这两种情况下,我都希望API响应仅来自受信任的移动应用程序的请求。

API也将用于通过移动应用程序注册新帐户。

更新2:似乎有多个答案,但是老实说,我不知道将哪个标记为答案。有人说可以做到,有人说不能做到。

评论

HTTPS使用SSL(和TLS)。 SSL / TLS可以与客户端身份验证一起使用。

您是指客户端SSL证书吗?我想这就是我要寻找的,除了我不知道在移动应用程序(Android和iOS)中是否还可以实现?客户证书将存储在哪里?设备存储,内存?

SSL仅会认证移动设备,而不认证移动应用程序。

@Supercell:我会添加一个答案

#1 楼

您不能。

您永远无法验证实体,任何实体,无论是个人,硬件客户端还是软件客户端。您只能验证他们告诉您的信息正确无误,然后假设是诚实。例如,Google如何知道我正在登录我的Gmail帐户?他们只是问我一个用户名和密码,进行验证,然后假设诚实,因为还有谁会得到该信息?在某个时候,Google认为这还不够,并添加了行为验证(寻找奇怪的行为),但这仍然依赖于该人执行该行为,然后验证该行为。

这恰恰是与验证客户端相同。您只能验证客户端的行为,而不能验证客户端本身。

因此,使用SSL,您可以验证客户端是否具有有效的证书,因此可以简单地安装您的应用,获取证书,然后运行所有新代码。

所以问题是:为什么这么关键?如果这是一个真正的问题,我会质疑您对胖客户的选择。也许您应该使用一个Web应用程序(这样就不必公开您的API)。

另请参见:击败Android应用程序的SSL证书验证

和:如何移动应用程序中的客户端SSL证书安全吗?

评论


我在硬件上使用了客户端证书,该证书存储在操作系统加密的驱动器上。但是即使在那儿,也没有人相信它是万无一失的。目标只是使休闲用户难以使用。

–机器人机器人
13年11月20日在19:40

@Morons:Web应用程序可以解决此问题,但我们认为用户比Web应用程序更可能使用本机应用程序(如果我们的假设错误,请更正我)。之所以如此重要,是因为API使用户可以访问我们数据库的各个部分,其中包含我们经过数月的工作收集的大量数据。这是其他公司或用户可以轻松用于自己目的的数据。如果没有保护客户,我们就不会知道谁在使用它(针对我们)。

–超级单元
13年11月20日在19:56

Webapp无法解决问题。修改任何webapp客户端并使其随心所欲是相当琐碎的。

–机器人机器人
13年11月20日在20:27

@Supercell您无法显示某人数据,然后阻止他们共享数据。如果您不希望某些人拥有数据,则不要将其提供(显示)给他们。

–白痴
13年20月20日在20:59

我同意,但出于不同的原因。如果您可以控制设备,可以有点帮助,例如en.wikipedia.org/wiki/SecurID。但是手机不是可以控制的东西(它们可以接受附件,例如插件密钥等)。

– imel96
13年11月21日在1:36

#2 楼

我确信您会适应用户登录以及通过SSL进行的通信,因此,我将重点关注我认为这是问题中最有趣的部分:如何确保只读操作-不需要用户进行身份验证-仅从您自己的客户端应用程序接受用户?

在进行其他操作之前,fNek在较早的答案中暗示了一个缺点-您的客户端应用程序位于潜在敌对用户之手。可以检查它们,检查它们的通信,反汇编其代码。我要提出的任何建议都不能保证您不会有人对您的客户端进行反向工程并滥用您的REST API。但这应该在任何偶然尝试之前都设置障碍。

无论如何,一种常见的方法是:


客户包含秘密
何时发出请求时,它将请求参数与密码连接起来,并对结果进行哈希处理。
此哈希与请求一起发送,并由服务器进行检查。

假设客户机密是“ OH_HAI_I_IZ_SECRET”

连接HTTP动词,URL和机密:

GET/products/widgetsOH_HAI_I_IZ_SECRET


并对其进行SHA-1哈希处理:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

然后发送,所以请求的对象是:

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02


最后,为防止某人至少重播单个请求,请同时添加一个时间戳,并将其添加到参数和哈希中。例如现在,在Unix时间是1384987891。将其添加到串联中:

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891


哈希值:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

<并发送:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1


服务器将检查哈希并验证时间戳是否是最新的(例如,在5分钟之内,以使时钟不能完全插入)同步)

警告!由于您在谈论移动应用程序,因此肯定存在某人的手机时钟错误的风险。或时区错误。或者其他的东西。将时间添加到哈希中可能会破坏一些合法用户,因此请谨慎使用该想法。

评论


任何程序员在拆解apk时都可以理解这种哈希机制。

– Punith Raj
15年7月9日在9:49

确实,@ PunithRaj在第二段中介绍了这一点。 “我要提出的任何建议都不能保证您不会有人对您的客户端进行反向工程并滥用您的REST API。但这在任何偶然的尝试之前都应设置障碍。”

– Carson63000
2015年7月10日,0:02

对于警告,正在服务器和移动设备上使用UTC,这可以解决问题,对吗?

– shareef
19年4月13日在6:34

@ Carson63000-那么,有没有具体的解决方案?特别是对于必须公开开放的用户注册API(用户需要先注册才能登录,无论是在Web上还是在移动应用程序上),并且僵尸程序可以将其作为目标以创建成千上万的假用户。

– Tohid
19年7月31日在7:21

#3 楼

对于有兴趣的人,在Android上,您可以验证您收到的请求是从您的应用发送的。

简而言之,当您将应用上传到Google时,您需要使用唯一的唯一密钥对它进行签名给你(和谷歌)。

验证过程如下:


您的应用转到Google并请求身份验证令牌
您的应用安全地发送了令牌到您的后端


您的后端去google并检查它从您的应用程序获得的身份验证令牌。
您的后端然后检查您的应用程序是否已签名了唯一密钥匹配,如果不是,则表示它不是您的应用... http://android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-android.html

评论


好的答案,但是恶意用户仍然可以尽力而为。但是没有什么是真正安全的,这不是问题的问题,只是时间的问题

–mateos
17 Mar 4 '17 at 15:11

对于iOS,有此选项:链接DeviceCheck API还可以让您验证收到的令牌是否来自已下载应用程序的真实Apple设备。

–艾瓦兹
17年11月5日,11:50

它需要帐户(电子邮件)

–user25
19年2月8日在22:53

#4 楼

好的,因此在我开始之前值得一提的是,对于大多数应用程序来说,这太过分了。对于大多数用例,仅拥有一个有效的证书和/或令牌就足够了。如果涉及到诸如反编译应用程序之类的艰巨任务,那么即使您没有提供一些非常有价值的数据,即使是大多数黑客也不会打扰。但是,嘿,答案的有趣之处在哪里?

那么,您可以做的是建立非对称密码,有点像用于对程序进行签名的数字签名。然后,每个应用程序都可以具有由单个CA颁发并在用户连接时进行验证的单独证书。 (在首次注册或首次安装时)通过该证书后,您可以通过将该证书注册为对一个给定设备标识符(例如Android ID)有效的证书来进一步保护您的应用程序

#5 楼

正如@Morons在回答中提到的那样,很难在连接的另一端验证实体。

提供某种程度的真实性的最简单方法是让服务器检查一些秘密,只有真正的实体才会知道。对于用户,这可能是用户名和密码。对于没有用户的软件,您可能会嵌入一个秘密。

这些方法的问题在于,您必须对客户端给予一定的信任。如果有人对您的应用程序进行逆向工程或窃取您的密码,他们可能会假扮您。

您可以采取措施,通过在可执行文件中对其进行混淆来使其更难以提取秘密信息。 ProGuard之类的工具是Java的混淆器,可以帮助解决这一问题,我对其他语言的混淆知之甚少,但可能还有类似的工具。使用TLS连接有助于防止人们窥探您的流量,但不能阻止MITM攻击。固定可以帮助解决该问题。

我为一家名为CriticalBlue(完全披露!)的公司工作,该公司的产品名为Approov试图解决这一信任问题。它目前适用于Android / iOS,并为我们的服务器提供了一种机制来检查客户端应用程序的完整性。它通过让客户端计算对随机挑战的响应来实现。客户端必须使用已安装的应用程序包的属性来计算响应,这些属性很难伪造,并且包括一些复杂的防篡改机制。

它返回一个令牌,然后您可以将其发送为证明您的API的真实性。

这种方法的重要区别在于,尽管可以在客户端上禁用真实性检查,但如果这样做,则不会获得需要使用服务器验证应用程序的身份验证令牌。该库还与其中包含的可执行文件的特性紧密相关,因此很难将其嵌入到伪造的应用程序中并使之正常工作。

任何成本/收益分析API开发人员必须确定某人试图破解其API的可能性以及成本如何。在应用程序中进行简单的秘密检查可以防止微不足道的攻击,但是保护自己免受更坚定的攻击者的侵害可能要复杂得多,而且成本可能很高。

#6 楼

SSL将确保通信通道的安全。

成功登录将通过加密连接发出身份验证令牌。

身份验证令牌将在所有后续请求中传递到REST API。

评论


我添加了一些其他信息。我打算像您提到的那样使用访问令牌进行身份验证。 REST API不需要用户登录,仅用于特定操作。在这两种情况下,都需要对客户端进行签名/信任。

–超级单元
13年11月20日在18:20



我对原生移动开发了解不多,但是您的移动应用程序可以将移动电话号码提供给REST API吗?当我在Android手机上安装应用程序时,经常会要求我授予该应用程序某些权限。如果可以通过安全连接向每个请求发送手机号码,则可以拒绝所有手机号码未知的请求。只是在这里大声思考...

– CodeART
13年20月20日19:41

这可能有效,但是这将要求用户登录并且该号码绑定到该用户帐户。否则,服务器将没有任何可用来验证数字的依据。

–超级单元
2013年11月20日19:50

您将如何安装移动应用程序?

– CodeART
13年11月21日在9:11

它们可以通过应用商店(Google,Apple,Microsoft)获得。

–超级单元
13年11月21日在10:41



#7 楼

它不是太安全,但是您可以添加某种秘密代码,甚至是数字签名。缺点:它必须包含在应用程序中,如果您知道自己的工作,就可以轻松获取它。

#8 楼


据我所知,HTTPS仅用于验证与之通信的服务器的身份。


实际上,您可以使用SSL对客户端和服务器进行身份验证。或者换句话说,“是的,您可以使用客户端证书”。

您需要...


查看您所使用的SSL库重新使用以确定如何在移动设备中指定客户端证书,
编写代码或配置HTTPS服务器,使其仅接受来自受信任的注册客户端的连接。
提出了添加受信任客户端的机制证书添加到服务器中
,提供了一种从服务器中删除不再受信任的客户端证书的机制

您可以让移动应用程序将证书存储在任意位置。由于需要特定于应用程序的身份验证,因此应考虑将证书存储在受保护的磁盘位置(在Android上,您可以在SQLite数据库中创建一个“ config”表,并为证书和私钥分别创建一行) 。