3

我想限制对我服务器上的 PHP 文件的访问。此 PHP 文件从 HTTP GET 请求中获取数据并将其附加到文件中。简单的。但是我不希望执行这个 PHP 文件,除非 HTTP 请求是从我开发的智能手机应用程序中生成的。

我不想单独验证每个用户。我希望我的应用程序,并且只有我的应用程序能够将请求发送到 PHP 文件。我不希望人们在浏览器中输入类似格式的请求 (http://www.mydomain.com/check.php?string=blahblahblah) 并产生相同的影响。

我曾考虑过检查 HTTP_USER_AGENT 或其他一些变量,但我担心它们也可能很容易被欺骗。我可以将一个密钥嵌入到我要查找的应用程序中,但该密钥也可能被泄露。

下一步是让服务器向我发送一个挑战,我会对此做出适当的回应。或者我什至可以研究 PKI。但是,考虑到我并不想保护任何真正有价值的东西,只是为了防止轻微的破坏行为,这是一种相对简单的方法。

我想在这里重新发明轮子吗?是否已经有一种简单、行之有效的方法来做到这一点?

4

7 回答 7

4

FWIW,这是我能想到的在不严重影响性能的情况下最安全的方法——本质上是 RESTful(ish) 方式,因为进一步提升它需要多个请求和存储在服务器上的连接状态信息:

  • 应用程序和服务器具有相同的硬编码盐字符串,对于移动应用程序的每个后续版本都是唯一的。此字符串必须保密。
  • 当用户在他们的设备上安装应用程序时,应用程序会联系您的服务器并通知它应用程序的版本和设备的IMEI,您正在使用的任何移动平台的 API 都应该能够让您检索。
  • 服务器为该应用程序实例生成一个唯一密钥,该密钥被发送回应用程序并存储在设备上,并将其与 IMEI 和安装的版本一起存储在服务器端数据库中。
  • 在日常操作期间(即提出问题中概述的请求时),应用程序遵循以下程序:
    • 检索以下信息:
      1. 设备 IMEI
      2. 应用密钥
      3. 应用版本
      4. 硬编码盐字符串
      5. 随机生成的附加盐字符串(当前时间戳的微秒导数对于合理数量的熵总是有益的)。
    • 将所有这些信息连接在一起,最好在它们之间使用硬编码填充并生成结果字符串的哈希。
    • 将以下信息与实际请求数据一起发送到服务器(可能在 cookie 中以增加一点安全性):
      1. 生成的哈希
      2. 应用密钥
      3. 随机生成的字符串用作附加盐
  • 服务器现在使用 App 密钥从数据库中检索该实例的设备 IMEI 和应用程序版本,并使用该信息以及版本 ID 的硬编码盐字符串和设备发送的附加盐字符串来构造哈希。如果服务器上生成的散列与移动设备生成的散列相匹配,则请求是好的,如果不是拒绝它。
  • 此过程中的所有通信都是通过 HTTPS 进行的。

为了突破这个系统并成功欺骗请求,攻击者需要知道以下内容:

  1. 设备 IMEI
  2. 应用密钥
  3. 应用版本
  4. 硬编码盐
  5. 用于生成散列的机制(输入字符串的精确格式和散列算法)。

显然,如果您使用的是移动设备,那么 1-3 很容易提取,但如果不对应用程序进行逆向工程,则无法找到 4 和 5(对于有知识和耐心的人来说,实际上没有什么可以阻止的)做)。

中间人攻击基本上是不可能的 - 即使在突破 SSL(至少可以说这很重要)并将应用程序逆向工程以获得 4 和 5 之后,如果没有 1-3 就无法检索对哈希的蛮力攻击,这非常复杂,平均需要数亿年(请参阅此页面以了解我如何得出该数字),特别是如果三者之一的长度可变 - 这应用程序版本字符串很容易。

于 2012-07-13T09:49:54.710 回答
3

在您的应用程序和 php 文件中定义一个盐,然后将该盐与当前时间相结合。这不太可能被欺骗。

$hash = sha1(time() . 'bladieblasalt');

if($_GET['hash'] == sha1(time() . 'samehash'))
{
    echo 'valid';
}
于 2012-07-13T08:53:42.490 回答
2

首先,您需要在您的应用程序中实现 ssl,否则一些知识很少的人可以简单地在 wifi 上连接手机,并使用 wireshark 或 cain 和 abel 等嗅探应用程序和您的网站之间的流量。并获取 url 和传递的任何参数,无需反汇编任何东西。

应用程序连接到您的站点并且用户登录,无论它是访客还是成员,您的服务器都会为应用程序分配一个请求 ID,并且此密钥/令牌与每个请求一起传递并在您的服务器上的会话中进行验证。

令牌看起来像: UNIQUE_REQUEST_ID_ASSIGNED_BY_SERVER:APPsIP:APPsTIME加密此字符串并将其作为$_GET['token']

然后在您的服务器上将字符串和字符串解密explode()为它的部分,并检查请求 id、ip 和时间匹配的数据库或会话等,如果一切都好的话。

就像一个安全的登录系统为每个用户分配一个唯一的盐,并将其存储在用户请求 ID 旁边。

底线是,让施虐者难以滥用系统。99% 的人甚至不会想去摆弄,而另外 1% 的人到达那里 ips 被阻止。

于 2012-07-13T09:17:52.607 回答
2

如果您不想要每个用户的任何东西,而只想要每个应用程序,那么您将不得不依赖应用程序中内置的秘密。任何反汇编应用程序的人最终都会发现这一点,所以一些混淆可能会有所帮助,但它不会让坚定的人离开你的页面。

也就是说,使用任何公钥加密都没有什么意义。由于应用程序端是欺骗者可能感兴趣的,他们已经可以访问密钥对中更有价值的一半。因此,您不妨使用一些使用共享密钥的方法。

您真正要检查的是传输数据的真实性。因此,只需获取该数据的核心(即所有真正重要的字段),将它们与共享秘密连接,散列结果并将其作为消息摘要传输。服务器执行相同的计算并检查计算的摘要是否与传输的摘要匹配。如果是这样,则该消息的发送者必须知道共享秘密。

重放攻击仍然存在一些机会,即有人记录了有效消息并稍后重复。您可以在服务器端检测完全重复的内容,并通过在消息的签名部分中包含时间戳来防止延迟重播。如果您的服务器允许客户端和服务器时间戳之间存在巨大差异,那么它将必须在相同的时间内保留重复的信息。如果它只接受小的差异,它可以使用较小的重复缓存,但设备配置错误的用户可能会感到恼火,因为服务器更有可能拒绝他们的请求太旧。

还有一点需要注意的是:您写了一个GET导致写入某个文件的请求。我总是将一些改变状态的操作与 a 联系起来POST。如果该应用程序是您自己的,则无关紧要,但是众所周知,浏览器会在GET不询问用户的情况下重新传输请求,从而导致对某些操作的重复请求。

于 2012-07-13T22:52:50.000 回答
1

没有保证方法。您可以使用 oauth 身份验证...根据您使用的平台以及将应用程序部署到手机的方式,也许您可​​以将密钥编译到应用程序本身中?任何东西都可以并且总是会被破解,没有 100% 的安全性......但尝试并不羞耻。:)

就我个人而言,我用于我的移动应用程序的是 RESTful 身份验证和常规登录/传递对基于令牌的通信,直到它过期。:)

于 2012-07-13T09:03:02.210 回答
0

HTTP 请求可以按照发送者想要的任何方式逐个字符地构建。欺骗总是可能的。

于 2012-07-13T08:51:38.557 回答
0

只需将授权(登录名、密码、会话等和/或“API 密钥”)添加到您的 PHP 应用程序,然后让您的手机应用程序先授权,然后再发送所需的请求。您可能没有考虑到这一点,因为如果您的脚本很简单,可能会给它添加一些混乱,但是几乎每个 Web 系统都需要它,并且您最终也会面临这个问题。

让您的手机应用程序通过 HTTPS 登录您的 PHP 应用程序以排除拦截。

于 2012-07-13T09:02:15.703 回答