1

我正在为正在开发的网站创建登录脚本,并使用 PHP 会话对用户进行身份验证。

我已将脚本设置为仅将 HTTP 用于 cookie,并且仅将 cookie 用于存储会话 ID。

基本上,我想知道两件事

1.我还应该做些什么来让我的登录更安全?

2. PHP 手册说session_destroy()删除会话数据,但不会取消设置任何会话变量。如果是这种情况,它实际上会破坏什么,我应该在注销时手动取消设置会话变量吗?

谢谢你的帮助

编辑: 我正在使用免费托管,无法安装任何 Apache 插件或更改 php.ini 文件

编辑: 我已经读到需要使用 SSL 来阻止会话 ID 被盗,但是我没有能力在服务器上安装 OpenSSL,那么还有其他方法可以保护会话 ID 吗?

4

5 回答 5

12

要记住的最重要的事情:

不要相信客户返回的任何东西

永远不要假设您获得的信息(在表单字段(甚至是隐藏的字段)、会话变量等中)是有效的 - 使用服务器端逻辑来执行这些检查。

1.) 确保您的会话已加密。如果您使用的是 PHP 的内置会话,则相关的熵(随机性)相对较高,所以应该没问题。

2.) 仅将会话 ID 存储在 cookie 中。任何其他信息都应该使用该 ID 在服务器上简单地关联。我见过很多情况,如果会话中的令牌'is_admin' = true,系统工程师会确定某人是否是管理员。您显然可以看到这个问题。

有些人会抱怨这是一项昂贵的操作,但我建议为活动会话创建一个(我的)SQL 表。然后,当页面加载时,从表中提取相关数据并像处理任何其他数据一样处理它。一些框架(如 CodeIgnitor)通过更改一个配置项为您完成此操作。

3.) 验证 IP - 在您的表中,添加当前 IP 地址。如果当前 IP 与会话中的 IP 不匹配,则可能有人试图劫持。强制注销并终止。

4.) 限制登录尝试。添加 1 秒 sleep(); 每次登录的服务器端对用户来说几乎是不明显的,但对于自动化系统,它几乎不可能暴力登录。

5.) 注意“太健谈”。在登录时,您可能认为提供描述性错误(例如“用户名不存在”或“密码不正确”)会有所帮助。这样的信息告诉黑客他们已经获得了一个有效的用户名——这使得黑客攻击更快。

6.) 少关注 PHP 和 SSL 的安全性,多关注你自己的逻辑。仅仅因为网站使用 SSL 并不能使其安全。SSL 与有效逻辑相结合提供了安全性。

7.) 如果你非常担心,你会想要转移到专用服务器。您服务器上托管的其他网站可能会访问您的代码/数据库信息。他们可能没有采取必要的措施来确保与您一样安全。

8.) 不允许同时进行会话。这可以防止 MITM(中间人)攻击。数据库会话方法的另一个优点是,如果两个客户端同时尝试从不同的 IP 登录,您可以强制注销。DB 方法的另一个优点是它使您的系统具有可扩展性(因为会话存储依赖于文件系统)。

9.) 使用 mysql_real_escape_string 而不是 add_slashes

如果您需要有关 PHP 安全性的更多信息,这是我的专长。随时联系我。

于 2010-12-19T02:35:53.257 回答
1

1)使用https。登录页面至少必须使用 https 来保护用户的密码,但您应该考虑让整个经过身份验证的会话使用 https 来防止 cookie 被窃取。

要求 cookie 和 POST 数据包含正确的身份验证令牌。

您还可以考虑更改每个请求的身份验证令牌以防止会话固定。我建议您阅读有关如何防止跨站点请求伪造和其他类似攻击的信息。OWASP是获取有关常见攻击以及如何缓解它们的一般信息的好资源。

2)session_destroy本质上使客户端的会话 cookie 无效,因此未来的请求将不会看到相同的会话数据。根据您的代码流,您可以session_destroy在返回客户端之前进行最后一件事,也可以手动取消设置$_SESSION超全局内容。

于 2010-12-19T02:19:48.510 回答
1

这里要了解的重要一点是数据的存储位置 - 会话存储在服务器端,因此会话中的任何内容都不会发送到客户端,除非您有意将其包含在页面中。Id 应该是随机的和不确定的(即不可猜测的)。

这意味着您可以使用会话来存储密钥、ID 等,而不必担心用户能够找出它们是什么。

当 you 时session_destroy(),您正在清除 Id 和使会话不可用的变量之间的服务器端链接。客户可能仍然有 ID,但它现在没用了。

如果不知道您实际在做什么,就不可能评论您的实施有多安全 - 但在会话中存储信息远比直接在 cookie/表单数据中好得多

编辑:关于您的 SSL 问题:

几乎所有现代服务器都支持 SSL。(你真的必须寻找不支持它的服务器)。OpenSSL 是实现 SSL的众多软件之一。

SSL 的基础知识如下: 您获得安装在服务器上的证书*。服务器使用此证书来“签署”每个请求并加密客户端和服务器之间的传输。

*证书可以免费创建(谷歌“自签名证书”),但自签名证书通常会给用户一个警告/错误,具体取决于浏览器(因为没有暗示信任级别)。浏览器有一个“受信任的”证书颁发者列表 - Verisign、Thawte 等等。这些是发行证书的成熟公司(通常是收费的)。

证书在一定时间段内有效,并且具有不同程度的信任(例如便宜的只是验证您的电子邮件地址是否正确,扩展验证证书仅在电话号码、护照、电子邮件地址和注册地址已由颁发者验证后颁发) .

EV 证书有一些优点(以及挂锁图标,您会看到一个绿色的地址栏 - 请参阅 www.paypal.com) 您需要确定这对您有多重要。

您应该联系您的主机询问是否/如何添加 SSL 证书。过去,这通常只适用于付费帐户,但现在它变得越来越普遍 - 所以如果你谷歌一下,你会喜欢找到免费的 SSL 托管

于 2010-12-19T02:13:47.027 回答
0

每次用户提升他们的权限级别(例如通过登录)时,我都会使用session_regenerate_id( ) 。我知道您说过您不能使用 SSL,但如果传输的信息非常敏感,您应该真正考虑一下。session_regenerate_id() 与 SSL 结合使用提供了对会话劫持的最强防御。如果您持有任何类型的敏感信息,您应该考虑免费托管是否真的可以满足您的需求。

于 2010-12-19T02:30:04.397 回答
0

我正在编写登录脚本,并按照@sethvargo 列出的每个步骤进行操作,如前所述,最重要的是检查数据是否由受信任的来源发送?我通常这样做的目的是创建一个特殊的令牌并将其嵌入到类似这样的形式中。

hash('md5', 'special-phrase_' . time() . '_special-phrase');

在接收端,我运行一个像这样工作的循环。令牌将在 1 分钟后失效。

for ($i=0; $i<=60; $i++) {
    $phrase = hash('md5', 'special-phrase_' . (time() - $i) . '_special-phrase');
    if ($phrase == $token) {
        print('Request received from a trusted client.'); exit;
    }
}
print ('Request timeout!')!

我在我的登录系统中使用了这种技术,这是处理可信数据的正确方法吗?请提出您的建议。谢谢!

于 2018-12-01T22:27:41.417 回答