【问题标题】:How to restrict access to a PHP file?如何限制对 PHP 文件的访问?
【发布时间】:2012-07-13 08:48:34
【问题描述】:

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

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

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

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

我想在这里重新发明轮子吗?是否已经有一种简单且经过验证的方法可以做到这一点?

【问题讨论】:

  • 根据您所做的事情的本质,没有 100% 万无一失的方法可以做到这一点。我能想到的最安全的事情是为您的移动应用程序的每个实例生成一个唯一密钥,在数据库中存储一个密钥列表 - > IMEI 关系以验证请求(显然包含此信息,最好以某种方式加密) 并通过 HTTPS 执行来自您的应用的所有请求。但即使这样,如果有人设法获得手机的密钥和 IMEI 对,它也将是欺骗性的。
  • 这个话题应该回答你的问题:stackoverflow.com/questions/2182936/…
  • 如果您想阻止自动机器人用垃圾淹没您的服务器,您可以将 PHP 脚本设置为在每次请求后休眠 30 秒。如果手机应用不需要响应(您可以使用 cURL 发送非阻塞请求),它会使机器人攻击变得冗长乏味,并且很容易通过 ip 发现和阻止。

标签: php http


【解决方案1】:

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

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

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

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

显然,如果您使用的是移动设备,则 1-3 很容易提取,但如果不对应用程序进行逆向工程,则无法找到 4 和 5(对于有知识和耐心去做)。

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

【讨论】:

    【解决方案2】:

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

    $hash = sha1(time() . 'bladieblasalt');
    
    if($_GET['hash'] == sha1(time() . 'samehash'))
    {
        echo 'valid';
    }
    

    【讨论】:

    • 盗版问题来自可能会拆解手机应用的人。
    • 另外,这将要求移动设备和服务器上的时间相同,并假设请求将花费
    • 您可以将其优化到 5 秒的范围,但如果您担心手机应用程序会被分解,我不知道您可以做什么。
    • 逆向工程是不可能解决的。如果你知道它在下面是如何工作的,你就可以闯入任何东西。但是我仍然不喜欢单独使用时间戳的想法,现在看着我的手机,时钟与我的电脑时钟相差 2 分钟,尽管我已经将它们都设置为从 pool.ntp.org 更新(两台设备上的 NTP 相同)。如果我手动强制更新,它们会重新同步,但我认为这证明了这一点并不足以成为一个可靠的选择。
    【解决方案3】:

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

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

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

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

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

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

    【讨论】:

    • IP 阻塞对移动设备来说是危险的,因为大多数移动网络 NAT 到几十万台设备可能共享少数公共 IP 的程度。由于一个人试图闯入系统,您有阻止许多用户的危险。
    • 是的,你的权利,虽然我认为任何伪造的请求都不会来自手机内部,但施虐者可以使用连接到笔记本电脑的手机连接仍然可行:s
    • 确实,或者只是一个 HSD/UPA 调制解调器。再加上移动平板电脑的发展方式,我可以看到在不远的将来人们会使用平板电脑而不是笔记本电脑。令人沮丧。
    【解决方案4】:

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

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

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

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

        • 如果你认为我错了,至少解释一下原因。我们都在这里学习。
        • 我没有对你投反对票,但我怀疑这样做的人不是因为这是错误的(不是),而是因为答案不够长。对于为什么,您没有提供任何真正的解释,也许您可​​以建议将风险降至最低的方法。要么,要么他们只是脾气暴躁/白痴。
        • @DaveRandom - 谢谢戴夫。它不会鼓励我在一个可以使用的地方使用两个词,但我同意你的观点。
        • 是的,我同意绝对没有必要使用包含少量信息的长文本来填充它,这完全取决于您在一天结束时提供的信息的质量。但在这种情况下,我认为可以合理增加数量,以帮助 OP 准确理解为什么他想做的事情或多或少是不可能的。
        【解决方案7】:

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

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

        【讨论】:

          猜你喜欢
          • 2012-04-03
          • 2013-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多