PHP - 如何限制客户端通过随机令牌访问其他 URL
PHP - How to restrict clients from accessing other URL by random token
来自 'domain1.com?secretkey' 的客户应该可以访问 'domain2.com'。
这些域位于具有不同网站空间和数据库的不同服务器上。
我在这里找到了 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';
}
但是如何生成单独的秘钥呢?
如果我在隐藏字段中使用硬编码令牌,我会知道该怎么做,但如何使用更安全的密钥?
使用 URL 参数发送令牌的常见加密方式有哪些?
So I guess I have to use a Token-URL-Parameter
这是一个明智的(如果不完美)选项。您需要在两个域之间共享一个不与浏览器共享的秘密。
这可以通过数据库完成,有两种可行的偏执方法。
Method one: Randomness
设置:
domain1.com
设置一个秘密密钥(见下文),该值与身份验证标准(如 IP 地址、日期时间、浏览器标识的哈希值)一起存储在数据库中 ($_SERVER['HTTP_USER_AGENT']
) , 以及任何你想用来更有选择性地验证密钥的东西不仅仅是侥幸。
- 数据库
理想情况下,数据库应与域位于同一台服务器上,并且只能在本地访问。但这是关于您真正想要的安全程度以及您想要在这个主题上投入多少 time/money/resources 的滑动比例。
如您所说明,此密钥通过您的 (urlencode
d) GET 参数传递给 domain2.com
。
- 编码:
base64_
不是必需的,但如果您想使用它也没有坏处。在 link URL.
中设置密钥时最好(必须)使用 urlencode($variable)
注意:您不需要在收到的 $_GET
变量上使用 urldecode()
.
- 如何生成个人秘钥?
密钥不应包含上述任何可识别信息,并且是纯随机的。它应该很长。这里的另一个答案引用了 8 个字符。这几乎会立即被打破。您希望生成尽可能长的密钥字符串。您可能仅受存储相同密钥的数据库 VARCHAR
列上的索引系统的限制。所以你需要一个 184 个字符的密钥,完全解码后。
- 获取密钥:
使用 random_bytes()
or openssl_random_pseudo_bytes()
,具体取决于您的 PHP 版本。
运行 在循环中生成密钥长度,并使用上面手册页中的示例将其设置为使用 bin2hex
或类似内容的字母数字字符串。
Do not use SHA1 or MD5 to generate hashes.
("Why not, sherlock?")
- 确保唯一性
获得密钥后,您需要检查它是否在数据库中。最简单的方法是构建数据库,使密钥列为 UNIQUE INDEX
(MySQL),因此如果有重复,则不会插入。您必须构建逻辑,以便如果密钥未插入,那么您应该重新启动并构建一个新密钥。
将密钥保存到数据库时,您还应该保存上面提到的其他元数据、IP 地址、浏览器哈希、日期时间等。
完成此过程后,您可以继续检查 URL 给定的 ey 是否有效。
得到:
- 正在验证随机字符串:
您的 $_GET
PHP 值中有密钥。将此密钥传递到您的数据库(当然,using Prepared Statements)并检查它是否存在。
- 验证和限定元数据:
一旦发现它存在,您可以检查元详细信息并确认它们是正确的。例如,调用请求的时间不超过数据库中用于创建行的日期时间值之后的 x 分钟数。
您检查哪些不一致以及您对哪些不一致做出反应取决于您,但举例来说,值得检查浏览器哈希是否相同,这样您就可以相当确定用于访问 domain1.com
的浏览器与访问 domain2.com
.
的浏览器相同
- 如何处理不一致?
那么,浏览器请求的字符串不存在?在踢出主页之前,在该条件下发出 5 秒 sleep()
声明。浏览器要求一个历史字符串(旧日期时间值),在踢出主页之前在上面敲击 sleep(5)
。等等等等
如果您愿意,您可以记录失败尝试的 IP 地址并使用它来计算(在另一个数据库中 table)任何重复尝试破解您的哈希值的 IP 块然后,您可以使用更多添加时间惩罚的代码,例如如果 205.453.345.xxx
IP 有 25 次失败尝试,则您可以向来自该 IP 的任何访问添加额外的 sleep()
,或者甚至对于更高的数字,只需踢掉该 IP 块而不用甚至懒得去检查散列。
不要向 user/browser 反馈任何特定哈希令牌失败的原因。探测攻击者可以使用此数据来计算更多关于您的哈希或元数据检查过程的信息。
警告:IP
在阻止或过度暂停 IP 时要格外小心,因为 IP 地址的使用人在不断变化。如果您按块 [123.456.678.xxx]
或按地址记录 IP 故障计数,则计数的存储时间不应超过 7 天。否则一个月前历史上属于黑客的 IP 将属于真正的用户,他们仍在遭受惩罚,而不是因为他们自己的过错。
在每个地址的基础上存储 IP 故障在磁盘空间上是昂贵的并且相对无用。块跟踪更有效。
- 清理
一旦您验证了密钥,并且元数据足够一致,您对此感到满意,请在 domain2.com
上设置 cookie/session 以允许该浏览器访问,然后删除来自数据库的哈希键,保留其独特的访问能力。
重要提示:
上面提到的一切都可以充分利用不完美的情况。应注意:
You cannot make a secure system by only providing an URL parameter, see: "" I know it's not exactly what you're doing, but the idea is the same. This problem can be solved, but it requires a lot of explanation and cautions.
这个特定主题比这个答案中的例子要多得多,但它需要奉献、阅读和学习。你将永远拥有一个完全安全的系统(这就像试图抓住云)所以你需要考虑你的风险是什么,它们有多重要以及值得花多少时间和精力去寻找缓解措施。
大多数安全性不是解决问题而是缓解问题。在上面的例子中,有可能泄露某个密钥,但它的可能性——在允许的时间内泄露一个密钥window,并使用据称相同的浏览器并使用相同的 IP 地址 -- 很小,但是绝对不是不可能.
Method two: Encryption.
不推荐。加密处理能力很强,与上面相同,但攻击更大window。
我能看到的在这里使用加密的唯一理由是,如果出于某些愚蠢的原因您无法使用数据库。因此,您可以制作元数据(IP、日期、时间等)的密文,然后将其发送到 domain2.com
以供 domain2.com 上的 PHP 以检查密文的比较。
例如,您通常放置的元数据是:
$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.
}
虽然这可行,但它也适用于任何填写正确密码详细信息的远程计算机,因为最终用户浏览器已经知道所检查数据的所有部分。
与数据库场景不同,没有独立的观察者。
This method is not recommended as it is processor heavy and potentially more vulnerable
一些来源 links:
- reliable user browser detection with php
当数据然后到令牌是随机的时,令牌是随机的。
用于数据的时间有一些弱点。数小时,数天,...,任何 url public 的时间都很难,并且相同的资源将相同,安全性降低。还有一个,它是时间更改密钥 4:00,任何 url 然后 3:59 如果在 4:00.
进行身份验证,则 wil 为假
我经常随机数组键并保存在环境中。然后url时,随机选择一个密钥==>传递给数据令牌并加密。验证时,我检查此数组中的键 ==> 通过
它涵盖了时间随机的所有弱点,你会很高兴的,谢谢 :D
来自 'domain1.com?secretkey' 的客户应该可以访问 'domain2.com'。 这些域位于具有不同网站空间和数据库的不同服务器上。
我在这里找到了 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';
}
但是如何生成单独的秘钥呢?
如果我在隐藏字段中使用硬编码令牌,我会知道该怎么做,但如何使用更安全的密钥?
使用 URL 参数发送令牌的常见加密方式有哪些?
So I guess I have to use a Token-URL-Parameter
这是一个明智的(如果不完美)选项。您需要在两个域之间共享一个不与浏览器共享的秘密。
这可以通过数据库完成,有两种可行的偏执方法。
Method one: Randomness
设置:
domain1.com
设置一个秘密密钥(见下文),该值与身份验证标准(如 IP 地址、日期时间、浏览器标识的哈希值)一起存储在数据库中 ($_SERVER['HTTP_USER_AGENT']
) , 以及任何你想用来更有选择性地验证密钥的东西不仅仅是侥幸。
- 数据库
理想情况下,数据库应与域位于同一台服务器上,并且只能在本地访问。但这是关于您真正想要的安全程度以及您想要在这个主题上投入多少 time/money/resources 的滑动比例。
如您所说明,此密钥通过您的 (urlencode
d) GET 参数传递给 domain2.com
。
- 编码:
base64_
不是必需的,但如果您想使用它也没有坏处。在 link URL.
urlencode($variable)
注意:您不需要在收到的 $_GET
变量上使用 urldecode()
.
- 如何生成个人秘钥?
密钥不应包含上述任何可识别信息,并且是纯随机的。它应该很长。这里的另一个答案引用了 8 个字符。这几乎会立即被打破。您希望生成尽可能长的密钥字符串。您可能仅受存储相同密钥的数据库 VARCHAR
列上的索引系统的限制。所以你需要一个 184 个字符的密钥,完全解码后。
- 获取密钥:
使用 random_bytes()
or openssl_random_pseudo_bytes()
,具体取决于您的 PHP 版本。
运行 在循环中生成密钥长度,并使用上面手册页中的示例将其设置为使用 bin2hex
或类似内容的字母数字字符串。
Do not use SHA1 or MD5 to generate hashes.
("Why not, sherlock?")
- 确保唯一性
获得密钥后,您需要检查它是否在数据库中。最简单的方法是构建数据库,使密钥列为 UNIQUE INDEX
(MySQL),因此如果有重复,则不会插入。您必须构建逻辑,以便如果密钥未插入,那么您应该重新启动并构建一个新密钥。
将密钥保存到数据库时,您还应该保存上面提到的其他元数据、IP 地址、浏览器哈希、日期时间等。
完成此过程后,您可以继续检查 URL 给定的 ey 是否有效。
得到:
- 正在验证随机字符串:
您的 $_GET
PHP 值中有密钥。将此密钥传递到您的数据库(当然,using Prepared Statements)并检查它是否存在。
- 验证和限定元数据:
一旦发现它存在,您可以检查元详细信息并确认它们是正确的。例如,调用请求的时间不超过数据库中用于创建行的日期时间值之后的 x 分钟数。
您检查哪些不一致以及您对哪些不一致做出反应取决于您,但举例来说,值得检查浏览器哈希是否相同,这样您就可以相当确定用于访问 domain1.com
的浏览器与访问 domain2.com
.
- 如何处理不一致?
那么,浏览器请求的字符串不存在?在踢出主页之前,在该条件下发出 5 秒 sleep()
声明。浏览器要求一个历史字符串(旧日期时间值),在踢出主页之前在上面敲击 sleep(5)
。等等等等
如果您愿意,您可以记录失败尝试的 IP 地址并使用它来计算(在另一个数据库中 table)任何重复尝试破解您的哈希值的 IP 块然后,您可以使用更多添加时间惩罚的代码,例如如果 205.453.345.xxx
IP 有 25 次失败尝试,则您可以向来自该 IP 的任何访问添加额外的 sleep()
,或者甚至对于更高的数字,只需踢掉该 IP 块而不用甚至懒得去检查散列。
不要向 user/browser 反馈任何特定哈希令牌失败的原因。探测攻击者可以使用此数据来计算更多关于您的哈希或元数据检查过程的信息。
警告:IP
在阻止或过度暂停 IP 时要格外小心,因为 IP 地址的使用人在不断变化。如果您按块 [123.456.678.xxx]
或按地址记录 IP 故障计数,则计数的存储时间不应超过 7 天。否则一个月前历史上属于黑客的 IP 将属于真正的用户,他们仍在遭受惩罚,而不是因为他们自己的过错。
在每个地址的基础上存储 IP 故障在磁盘空间上是昂贵的并且相对无用。块跟踪更有效。
- 清理
一旦您验证了密钥,并且元数据足够一致,您对此感到满意,请在 domain2.com
上设置 cookie/session 以允许该浏览器访问,然后删除来自数据库的哈希键,保留其独特的访问能力。
重要提示:
上面提到的一切都可以充分利用不完美的情况。应注意
You cannot make a secure system by only providing an URL parameter, see: "" I know it's not exactly what you're doing, but the idea is the same. This problem can be solved, but it requires a lot of explanation and cautions.
这个特定主题比这个答案中的例子要多得多,但它需要奉献、阅读和学习。你将永远拥有一个完全安全的系统(这就像试图抓住云)所以你需要考虑你的风险是什么,它们有多重要以及值得花多少时间和精力去寻找缓解措施。
大多数安全性不是解决问题而是缓解问题。在上面的例子中,有可能泄露某个密钥,但它的可能性——在允许的时间内泄露一个密钥window,并使用据称相同的浏览器并使用相同的 IP 地址 -- 很小,但是绝对不是不可能.
Method two: Encryption.
不推荐。加密处理能力很强,与上面相同,但攻击更大window。
我能看到的在这里使用加密的唯一理由是,如果出于某些愚蠢的原因您无法使用数据库。因此,您可以制作元数据(IP、日期、时间等)的密文,然后将其发送到 domain2.com
以供 domain2.com 上的 PHP 以检查密文的比较。
例如,您通常放置的元数据是:
$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.
}
虽然这可行,但它也适用于任何填写正确密码详细信息的远程计算机,因为最终用户浏览器已经知道所检查数据的所有部分。
与数据库场景不同,没有独立的观察者。
This method is not recommended as it is processor heavy and potentially more vulnerable
一些来源 links:
- reliable user browser detection with php
当数据然后到令牌是随机的时,令牌是随机的。 用于数据的时间有一些弱点。数小时,数天,...,任何 url public 的时间都很难,并且相同的资源将相同,安全性降低。还有一个,它是时间更改密钥 4:00,任何 url 然后 3:59 如果在 4:00.
进行身份验证,则 wil 为假我经常随机数组键并保存在环境中。然后url时,随机选择一个密钥==>传递给数据令牌并加密。验证时,我检查此数组中的键 ==> 通过 它涵盖了时间随机的所有弱点,你会很高兴的,谢谢 :D