PHP - 如何限制客户端通过随机令牌访问其他URL

时间:2017-10-02 12:22:34

标签: php authentication url-parameters restriction

来自' domain1.com?secretkey'的客户应该可以访问' domain2.com'。 这些域位于不同的服务器上,具有不同的websspace和数据库。

我在这里找到了3种限制网页的方法: wmtips.com/php/simple-ways-restrict-access-webpages-using.htm

我无法使用用户名和密码进行身份验证,所以我想我必须使用 Token-URL-Parameter 和这样的函数:

//This function returns True if query string contains secretkey and secretvalue.

//Otherwise it returns False

function CheckAccess()

{

  return $_GET['secretkey']=='secretvalue';

}

但是如何生成一个单独的密钥?

如果我在隐藏字段中使用硬编码令牌,我会知道该怎么做,但如何使用更安全的密钥?

使用网址参数发送令牌的常见加密方式是什么?

2 个答案:

答案 0 :(得分:0)

  

所以我想我必须使用 Token-URL-Parameter

这是一个明智的(如果不完美的)选项。您需要在两个域之间共享一个未与浏览器共享的秘密。

这可以通过数据库完成,有两种可行的偏执狂方法。

  

方法一:随机性

环境:

domain1.com设置一个密钥(见下文),该值与验证标准一起存储在数据库中,例如IP地址,日期时间,浏览器标识的哈希值($_SERVER['HTTP_USER_AGENT']),以及无论你想用什么来更有选择性地验证密钥都不仅仅是一个幸运的侥幸。

  • 数据库

理想情况下,数据库应与域名在同一服务器上,并且只能在本地访问。但这是一个滑动的尺度,关于你真正想要的安全性以及你想在这个主题上投入多少时间/金钱/资源。

如您所示,此密钥会通过您的{domain2.com d) GET 参数传递给urlencode

  • 编码:

base64_不是必需的,但如果您想使用它,那就没有害处。在链接URL中设置密钥时,使用urlencode($variable)会更好(必需)。

注意:您无需对收到的urldecode()变量使用$_GET

  • 如何生成个人密钥?

密钥不应包含任何上述可识别信息,并且纯粹是随机的。它应该很长。这里的另一个答案引用了8个字符。这将几乎立即打破。您希望尽可能长地生成密钥字符串。您可能只受数据库中存储相同密钥的VARCHAR列的索引系统的限制。因此,在完全解码时,您需要184个字符的密钥。

  • 获取密钥:

使用random_bytes()openssl_random_pseudo_bytes(),具体取决于您的PHP版本。

在循环上运行此操作以生成密钥长度,并使用上面手册页中的示例将此设置为使用bin2hex或类似字符串的字母数字字符串。

  

不要使用SHA1或MD5生成哈希值。

     

(" Why not, sherlock?")

  • 确保独特性

获得密钥后,您需要检查它是否在数据库中。最简单的方法是构建数据库,使secretkey列为UNIQUE INDEX MySQL ),因此如果重复,则不会插入。您必须构建逻辑,以便在未插入密钥的情况下,您应该重新启动并构建新密钥。

将密钥保存到数据库时,还应保存其他元数据,如上面所述,IP地址,浏览器哈希值,日期时间等。

完成此过程后,您可以继续检查给定的URL是否有效。

获得:

  • 验证随机字符串:

您的$_GET PHP值中包含密钥。将此密钥传递给您的数据库(当然,using Prepared Statements)并检查它是否存在。

  • 验证和验证元数据:

一旦您发现它存在,您可以检查元数据并确认它们是否正确。例如,在数据库中创建行的日期时间值之后,调用请求的时间不超过x分钟。

您检查的哪些不一致以及您对此做出的反应取决于您,但举例来说,值得检查浏览器哈希是否相同,以便您可以相当确定用于访问domain1.com的浏览器与访问domain2.com的浏览器相同。

  • 如何处理不一致?

那么,浏览器请求一个不存在的字符串?在开始进入主页之前,在这个条件下敲了5秒sleep()声明。浏览器要求输入历史字符串(旧的日期时间值),然后在踢出主页之前敲打sleep(5)。等等。

如果您愿意,可以记录失败尝试的IP地址,并使用它来计算(在另一个数据库表中)任何反复尝试破解哈希的IP块,然后,您可以使用更多代码来增加时间惩罚例如,如果205.453.345.xxx IP有25次尝试失败,则可以向该IP的任何访问添加额外的sleep(),或者甚至更高的数字只需踢掉那个IP块,甚至无需检查哈希值

请勿向用户/浏览器反馈任何特定哈希令牌失败的原因。探测攻击者可以使用此数据来计算有关哈希或元数据检查过程的更多信息。

警告:IP

要小心阻止或过度暂停IP,因为使用IP地址的人会不断变化。如果按块[123.456.678.xxx]或按地址保留IP故障计数,则不应将计数存储的时间超过7天。否则一个月前历史上属于黑客的IP将属于真正的用户,他们仍然遭受处罚,而不是他们自己的错。

在每个地址的基础上存储IP故障在磁盘空间中是昂贵的并且相对无用。块跟踪更有效。

  • 清理

一旦您验证了密钥,并且元数据足够一致,您就会对它感到满意,请在domain2.com上设置Cookie /会话以允许该浏览器访问然后删除来自数据库的hashkey,保留其唯一的访问能力。

重要:

上面提到的所有内容都可以充分利用不完美的情况。应注意comment by KIKO Software

  

您只能通过提供网址参数来建立安全系统,请参阅:" https url with token parameter how secure is it?"我知道这不完全是你在做什么,但这个想法是一样的。这个问题可以解决,但需要大量的解释和注意事项。

这个特定主题比这个答案中的例子还多,它需要奉献精神,阅读和学习。你将从不拥有一个完全安全的系统(它就像试图捕捉云)所以你需要考虑你的风险是什么,它们有多重要以及它们需要多少时间和精力# 39;值得寻找缓解措施。

大多数安全措施不是解决问题,而是减轻问题。在上面的示例中,可能会破坏某个密钥,但是它的可能性 - 在允许的时间窗口中使用一个密钥来配置密钥并使用相同的IP浏览器并使用相同的IP地址 - 非常小,但绝对不是不可能

  

方法二:加密。

不推荐。加密处理能力很重,与上面相同但攻击窗口要大得多。

我可以看到在这里使用加密的唯一原因是,如果出于某种愚蠢的原因,您无法使用数据库。因此,您可以创建元数据的密文(IP,日期,时间等),然后将其发送到domain2.com上的PHP的domain2.com以检查密文的比较。

比方说,例如,您通常会提供的元数据是:

$plainText = $_SERVER['REMOTE_ADDR'].date("Y-m-d").md5($_SERVER['HTTP_USER_AGENT']);
$options = [  'cost' => 12,];

$cypher = password_hash($plainText, PASSWORD_BCRYPT, $option ); 
$urlCypher = urlencode($cypher);

要在domain2.com阅读,请使用:

$checker = $_SERVER['REMOTE_ADDR'].date("Y-m-d").md5($_SERVER['HTTP_USER_AGENT']);

if(password_verify($checker,$_GET['keystring'])){
      //values compare ok.
}

虽然这有效,但它也适用于填写正确密码详细信息的任何远程计算机,因为所检查数据的所有部分都已为最终用户浏览器所知。

与数据库场景不同,没有独立的观察者。

  

建议不要使用此方法,因为它处理器很重且可能更容易受到攻击

一些来源链接:

答案 1 :(得分:0)

当到令牌的数据是随机的时,令牌是随机的。 用过的时间来数据有一些弱点。时间很难持续数小时,数天,...,这段时间内公开的任何url,并且相同的Resource将相同,安全性降低。再更改一次,将时间更改为4:00,如果在4:00进行身份验证,则任何3:3-5网址都将为假。

我经常将随机数组键保存在env中。然后输入url时,随机选择一个键==>传递给数据令牌并加密。验证时,我检查此数组中的键==>通过 它涵盖了时间随机性的所有弱点,您会对此感到满意的,谢谢:D