仅当请求来自其他特定网站时才允许登录网站

时间:2014-12-05 19:51:23

标签: php login referrer

我有一个PHP / MySQL网站(网站1),它有一个只需要输入PIN码的登录系统(只是一个长数字字符串)。用户有两种使用此代码登录的方式:

  1. 转到网站1登录页面并以典型登录表单输入代码
  2. 在链接上点击网站2,该链接将其PIN码作为GET值。该链接的格式为http://myURL.com/login.php?pin=123456789。这只是调用一个接收PIN作为参数的函数并处理登录。 网站2位于与网站1不同的域/服务器
  3. 直到这里一切正常。

    现在来问题了。我想知道在使用上述第二种方法时,是否可以只允许登录(假设PIN是正确的)仅在特定网站点击该链接

    现在的工作方式,任何有链接的人都可以使用它来登录网站1.我想阻止这一点,如果点击链接赢得网站2,我想允许这种情况发生。

    这个想法是"检测"登录功能中的引用网站,只有与网站2的URL(或任何其他唯一标识符)匹配时才允许。

    如果使用" plain"链接不允许这不是一个问题,我可以灵活地使用什么方式,但最终它需要是一个只对用户点击的东西在网站2中。

    修改

    我认为添加这个很好,因为一些评论/回复谈到了这样做的安全性(这当然很棒)。这样做的主要原因是" force"用户在访问网站之前访问网站1.基本上,他们无法在浏览器中输入该URL并登录网站1,我希望只有在他们点击它时才能使用该链接我解释了这一点,因为安全性不是一个很重要的因素,如果一些精明的用户可以绕过我实施它的任何方法并不是什么大不了的事,那么这个方法更重要的是尽可能简单地在网站2中实施(因为我不会运行该网站,我需要让那里的人做任何需要的事情)。

3 个答案:

答案 0 :(得分:4)

我认为您正在寻找单点登录的变体。这是一种技术,其中一个站点中的认证在另一个站点中透明地被识别。以下是它的工作原理。

通常你会在site2.com上有这样的链接:

  

http://site1.com/login.php?pin=123456789

然而,site1.com无法从推荐人那里知道它真正来自哪个网站,因为它可以轻易伪造。当然,如果您只想要一个简单的安全级别,这对您的用例可能无关紧要。但如果你想要更好的东西,请继续阅读!

您可以使用散列系统和共享密钥来创建只能来自一个来源的内容。两个站点都具有相同的共享密钥,存储在文件中。我们称之为$sharedSecret。算法如下:

$hash = hashFunction($pin . $sharedSecret);

然后你可以在site2.com上做到这一点:

<a
    href="http://site1.com/login.php?pin=<?php echo (int) $pin ?>&amp;hash=<?php echo $hash ?>"
    alt="Authenticated link"
>

当site1.com看到它时,它可以立即获得PIN,重复算法,并检查散列是否确实来自site2.com。如果您有多个引用网站,那么site1.com应该为所有网站存储一个单独的密码,然后它可以安全地检查引荐来源以查看它应该加载哪个。

共享秘密应该足够大,无法猜到;我倾向于约40-60个字符。

然而,这个计划的剩余缺陷是有人可以访问site2.com并从他们那里窃取链接,并且它仍然可以工作,前提是他们也愿意每次想要访问时伪造推荐人。因此,在算法中添加时间戳可能很有用:

// The time is rounded to the nearest 500 seconds, to account for
// out of sync clocks. Adjust this depending on how long you want links to
// remain active for
$time = floor(time() / 500) * 500;
$hash = hashFunction($pin . $sharedSecret . $time);

然后在site1.com上你应该计算两个哈希值:

  • 一个用于floor(time() / 500) * 500
  • 一个用于floor(time() / 500) * 500 - 500

如果提供的哈希匹配,则允许链接解锁内容。这说明一个服务器和下一个服务器之间的时间超过+/- 500边界的可能性。

我还没有在这里提到特定的散列函数。 SHA256应该没问题,但请注意我不是密码学家。如果你想再次获得更高的安全性,可能值得检查以确保有人不会通过猜测来强制系统 - 尽管在互联网上很难尝试。

答案 1 :(得分:0)

问题是多方面的。 $ _SERVER [&#39; HTTP_REFERER&#39;]可供PHP使用,但可以被欺骗或省略,并被视为不可靠。

跨域cookie也是一个挑战;我理解它是可能的,但还没有时间来实现它(我们在工作中有一个用例)。无论如何,cookies也很容易被利用。

可能你最好的选择是将链接指向&#34;网站A&#34;指向资源也位于&#34;网站A&#34;将随机密钥/令牌和时间戳设置到共享数据库中,并将浏览器发送到&#34;站点B&#34;有那个令牌。接收页面位于&#34;站点B&#34;然后将验证GET字符串中是否存在密钥/令牌,检查它是否存在于数据库中,并可能匹配User-Agent和Referer数据,并检查该密钥的时间戳条目后的时间是否在$ smallnum秒内/令牌。

答案 2 :(得分:0)

由于其他SO用户提出的其他答案/评论,我将发布我的答案。我认为这是一个非常简单的方法(在这种情况下简单性很好),它应该可以工作,但当然如果它有任何重大缺陷我会很高兴知道:)

就像我在OP中所说的那样,安全性(就一些精明的用户而言,直接使用链接而不是网站2)在这里并不是一件大事,我们可以处理少数例外情况。

以下是这个想法:

  • 为网站2中的用户提供指向同一域中的功能的链接
  • 该函数获取每个用户将拥有的PIN(即1234567890)和当前时间戳(即1417812842),使用这两个值创建令牌,使用两个网站都知道的另一个函数(使用盐进行某种散列) ,例如)
  • 生成从网站2到网站1的重定向,其中包含PIN和令牌的网址,例如:http://myURL.com/process_login_request.php?pin=123456789&token=abc123def456
  • process_login_request.php中的一个函数,使用与在网站2中生成令牌相同的函数,将使用PIN和生成过去X秒(比如说10秒)生成许多令牌。过去10秒的时间戳。
  • 如果任何生成的令牌与收到的令牌匹配,则表示请求正常,我们允许登录

我认为实施起来比解释更容易。这个想法基本上是我们在很短的时间内使用时间戳(用户“点击”应该将他带到网站1的链接和他实际登陆网站1的时间之间的时间)。我说10秒,但如果10秒太短(我认为不应该这样),我们可以根据需要增加它。

相关问题