Logging In: Background Details
当你登录一个网站时会发生什么?
我知道曲奇是存储的,还有一些信息(什么信息?)被发送到服务器…但也许还有更多细节?
从前,在互联网的某个地方…
- 浏览器:"嘿,我能看看这个网页吗?"问题是,我不记得以前跟你说过"
- 网站:"当然,填写表格,我需要你的用户名和密码。"
- 浏览器:"给你"
- 网站:"太好了!欢迎回来!这是页面。看,如果你想要更多的页面,拿着这个令牌,在你要求另一个页面时使用它。"
- 浏览器:酷。那个网站给了我一个代币。我会记住的!
几分钟后
- 浏览器:"哦!我能看一下这另一个网页吗?这是我的代币"
- 网站:"代币看起来不错,再次向Koldfyre问好,这是您的网页。"
本质上,就是这样。为了记住用户已登录,它向用户提供一个令牌,该令牌必须与下一个请求一起提供。这通常是通过服务器告诉浏览器将此令牌存储在cookie中来实现的。
深入研究传输层身份验证凭证传递到服务器的方式及其返回的令牌的性质取决于所采用的身份验证方法。
最简单的HTTP基本身份验证是由大多数Web服务器实现提供的。它会使浏览器弹出熟悉的登录对话框。"令牌"只是您的纯文本用户名和密码base64编码。不是特别安全。
服务器还可以提供摘要式身份验证,这样可以避免实际凭证的传输——客户机使用服务器生成的salt生成其凭证的散列。它旨在防止密码嗅探和重放攻击。
更深层次的应用层身份验证为了实现最大的灵活性和控制,大多数站点选择在应用程序层而不是HTTP传输层中实现授权。这提供了更广泛的安全选择。任何要求在网页(而不是浏览器的登录对话框)中提供凭据的网站都使用自定义授权方法。
自定义方法在最初的交互中会有很大的变化,但它们几乎总是会导致用户得到一个包含随机生成的标识符的会话cookie。然后浏览器会自动向cookie显示每个后续请求。Web应用程序将检查cookie值以确保它仍然有效。
还可以将授权移交给受信任的第三方,通常提供某种单一登录服务。在这种情况下,当您注意到一个用户没有经过身份验证时,您会将其退回到身份验证提供者。它们对它们进行身份验证,并将使用您与提供者验证的某种令牌返回给您。Shibboleth就是一个例子。您还使用OpenID使用的类似方法登录了这个站点。
进一步阅读下面是一个类似问题的一些很好的答案
- 第一部分:如何登录
- 第二部分:如何保持登录-臭名昭著的"记住我"复选框
- 第三部分:使用秘密问题
- 第四部分:忘记密码功能
- 第五部分:密码强度检查
- 第六部分:更多-或:防止快速登录尝试
- 第七部分:分布式暴力攻击
这个问题的其他答案提供了更多的链接来完善你的教育!
这是一个相当普遍的问题。总之,您所做的就是在站点本身建立某种凭证。如果我们使用简单的版本,您输入用户名和密码;这意味着您在网站上标识自己,然后向其显示您和网站共享的秘密,其他人都不知道(我们希望如此)。这证明你是那个用户名的真实用户,所以我们说你已经验证了你自己。
一旦你这样做了,网站设计师必须做出一些设计决定。大多数人不想为每一页登录,所以网站想在你的终端存储一些信息,一个凭证。这意味着它可以分辨出它仍然是你。通常,正如您所说,这是一个"cookie",它只是一个以网站的URL命名的小文本文件。此文件由浏览器存储。
在许多网站上,比如银行业,您还希望保证所交换的数据不会被第三方截取。如果是这样,您可以使用称为ssl或tls的协议建立安全连接。这增加了基本连接的内容是建立会话密钥的信息交换。然后使用此会话密钥加密通信。这通常发生在您交换用户名和密码之前,这样恶意的第三方也就不会看到您的密码。
在封面下,当您建立安全连接时,网站会向您的浏览器发送一个称为X509证书的格式化数据块。这是另一种身份验证形式;证书将由颁发者(证书颁发机构或"CA")签名,浏览器可以使用有关CA的存储数据来确保证书的真实性。
这完全取决于网站的实现。即使使用cookie也不是强制性的,但非常常见。
然而,在大多数情况下,类似的事情会发生:
- 使用HTML表单发送用户名和密码。
- 服务器查找相关用户(使用数据库)
- 服务器检查密码是否与存储在数据库中的用户密码匹配。
- 如果密码正确,服务器将存储会话中当前处于活动状态的用户。此会话的标识符存储在cookie中,此会话的实际数据(当前用户)存储在此标识符下的服务器上。
现在您已登录。您将在会话的剩余时间内保持登录状态:
- 当您从服务器请求另一个页面时,您将发送带有sesison标识符的cookie。
- 服务器使用此标识符加载会话。在此会话中,将存储当前用户,因此服务器知道登录的是哪个用户。
当您登录到一个网站时,首先验证您的凭证。如果您的凭据匹配,则会在会话(在服务器上)中放置一些内容以跟踪您是谁,这样您就可以访问属于您的数据,而无需重新登录。这在Web服务器上显然是无用的,除非客户机可以提供有关每个请求上的信息。注意,"会话"通常完全在Web服务器上维护,客户机只有一个允许访问会话的密钥。
记住,HTTP本身是一个无状态协议。HTTP标准不包含HTTP请求保持或保持单个HTTP请求之间任何状态的方法。因此,状态通常完全保存在服务器上,您只需要一个方法让客户机识别当前HTTP请求属于哪个会话。
实现这一点的两种常见方法是:
- 使用cookie(例如,apache tomcat使用
JSESSIONID cookie)来存储一些将成功查找Web会话的哈希认证令牌,或者 - 重写URL,使每个请求的会话ID都添加到请求的末尾。仍然以ApacheTomcat为例,如果禁用cookies,那么URL将被重写为以"
;jsessionid=.... 之类的字符串结尾。因此,每个请求、每个HTTP GET和POST(以及其余)都将以该字符串结束。
因此,在客户机发出的每个请求上,会话ID都提供给Web服务器,允许快速查找此客户机的持久状态,从而允许HTTP像一个有状态的协议一样工作。
登录时会向服务器发送哪些信息?您在登录表单上提供的任何信息。一些Web服务器还跟踪请求来自的TCP/IP地址,以避免会话劫持攻击。这通常是服务器需要的所有信息。
如果不允许浏览器保存cookie,则每次打开浏览器并最初打开服务器的网页时,都必须登录到Web服务器。但是,如果您允许浏览器保存cookie,那么许多服务器允许您选择保存cookie(即,不只是使用会话cookie),以便每次访问服务器的网页时,持久化cookie都会识别您,这样您就不需要重新登录。在这里,cookie将保存足够的信息——通常以只有服务器能够理解的加密形式——来识别您。在本例中,cookie不是简单的会话ID。
在Web上执行身份验证的主要方法有两种,还有一些不太流行的方法也值得了解。
第一个是HTTP身份验证,如RFC2617所定义。当您请求一个受保护的页面时,服务器用一个
HTTP身份验证是一种古老的功能,浏览器从一开始就没有很好地实现,而且从未真正改进过。正因为如此,Web开发人员使用cookie来持久化状态,从而自行实现身份验证变得越来越流行。在这种情况下,用户将看到一个标准的HTML表单。当用户在字段中输入凭证并提交表单时,浏览器会对其进行编码,并以与对任何普通HTML表单进行编码相同的方式将其发送到服务器。服务器检查凭证,如果它们是合法的,则使用随机生成的ID号以及相应的数据库/文件系统条目设置一个cookie,该条目识别出该ID号属于特定用户。
从现在开始,浏览器向服务器发出的每一个请求都将这个ID号cookie作为一个HTTP头。服务器识别cookie,查找ID号,并知道您是哪个用户。当您选择注销时,服务器会发送一个响应,要求您的浏览器忘记ID号,此时您只是另一个匿名用户。
较不常用的选项是使用SSL客户机证书。许多人都熟悉使用SSL来标识服务器的想法。生成一个加密密钥对,由受信任的颁发机构签名,用于证明发送的数据来自密钥对的所有者。然而,许多人不知道的是,客户机也可以用它向服务器证明自己的身份。但是,这不太方便,因为如果要在多台计算机上使用证书,您需要随身携带它。
当然,也有一些变种和鲜为人知的选择,但这些是最突出的选择。
非常简单的解释如下:
什么进去了?- 用户名
- 密码
里面发生了什么?
- 此令牌只能包含状态、登录时间戳、用户ID、用户类型(如果有)等。
- 如果您访问的每个页面要求您作为特定类型的用户登录,则会在该页面上读取和验证此令牌。
出什么事了
听着,要给你提供更多你已经掌握的信息有点困难,我不知道你为什么要悬赏。一个cookie只是一点命名信息,你可以把你喜欢的任何东西放进去。对于会话,您需要某种类型的会话ID。这有一些约定,或者您可以自己做。无论您做什么,当您设置cookie时,您都会在用户的浏览器上留下一些或多或少类似的数据:
1 2 | mydomain.com: mystuff: this is my stuff, by golly. |
当你回来的时候,你把饼干拿回来。
如果你想了解该协议的所有细节,可以看看维基百科的文章。
正如其他人提到的,登录过程因实现而异,但基本情况(简单的Web应用验证)使用类似以下伪代码的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function login(username, password) { user = db->get_user(username) if (user == false) { report_error("Unknown username") exit } if (user->password != hash(password)) { report_error("Incorrect password") exit } // User authenticated, set session cookie session->set_data('current_user', user->username) } |
当然,在大多数情况下,它比这要复杂一点,但是每个登录函数开始的时候基本上都和上面一样。现在,如果我们将autologin("remember me")添加到混合中,我们得到如下结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function login(username, password, remember_me) { user = db->get_user(username) if (user == false) { report_error("Unknown username") exit } if (user->password != hash(password)) { report_error("Incorrect password") exit } // User authenticated, set session cookie session->set_data('current_user', user->username) if (remember_me == true) { cookie_token = random_string(50) set_cookie('autologin_cookie', cookie_token, ONE_MONTH) // Finally, save a hash of the random token in the user table db->update_user(user, 'autologin_token', hash(cookie_token)) } } |
号
加上在存在cookie时执行自动登录的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function cookie_login() { cookie = get_cookie('autologin_cookie') if (cookie == false) { return false } // Only for demonstration; cookie should always include username as well user = db->get_user_by_cookie(cookie) if (user == false) { // Corrupt cookie data or deleted user return false } // User authenticated, set session cookie session->set_data('current_user', user->username) return true } |
注意:上面的方法不是"最佳实践"方法,也不是很安全。在生产代码中,您将始终在cookie数据中包含一个用户标识符,使用多个级别的限制,在失败和成功登录时存储数据,等等。所有这些都已被剥离,以简化身份验证的基本结构。
不管怎样,我希望这就是你要找的,科尔德菲尔。我不知道你的背景,但是如果你不确定会话和cookie是如何工作的,你应该单独阅读它们,如果你需要更详细的细节,就问问。
P.S.:您可能还想检查"网站认证最终指南"的问题,了解最佳实践方法。