传统Web应用程序和API中的身份验证,授权和会话管理


75

如果我错了,请纠正我:在传统的Web应用程序中,浏览器会自动将会话信息附加到服务器的请求中,以便服务器可以知道请求的来源。实际上究竟附加了什么?

但是,在基于API的应用程序中,此信息不会自动发送,因此在开发API时,我必须检查自己(例如,请求是否来自经过身份验证的用户)?通常如何做?


1
我希望您没有基于浏览器将正确管理会话的假设来开发以前的Web应用程序。

2
@bor,我不确定自己是否做得正确,但是我确定可以。以前我使用PHP,所以我刚刚检查了$_SESSION,对吗?到目前为止,我发现它工作正常。似乎浏览器将处理会话/ cookie?
揭蒙

Answers:


122

HTTP协议在设计上是无状态的,每个请求分别完成,并在单独的上下文中执行。

会话管理的思想是将来自同一客户端的请求置于相同的上下文中。这是通过服务器发布标识符并将其发送给客户端来完成的,然后客户端将保存该标识符并在后续请求中重新发送它,以便服务器可以识别它。

饼干

在典型的浏览器-服务器情况下;浏览器管理每个域的键/值对列表,称为cookie:

  • Cookie可以由服务器使用Set-CookieHTTP响应标头来管理(创建/修改/删除)。
  • 服务器可以通过解析CookieHTTP请求标头来访问(读取)cookie 。

以Web为目标的编程语言/框架提供了在更高层次上处理cookie的功能,例如,PHP提供setcookie/$_COOKIE编写/读取cookie。

届会

回到会话,在典型的浏览器-服务器情况下(再次),服务器端会话管理利用了客户端Cookie管理。PHP的会话管理设置一个会话ID cookie,并使用它来标识后续请求。

Web应用程序API?

现在回到您的问题;由于您将负责设计API和对其进行文档化,因此实施将由您决定。你基本上必须

  1. 通过Set-Cookie响应正文(XML / JSON身份验证响应)中的HTTP响应标头为客户端提供一个标识符。
  2. 具有维护标识符/客户端关联的机制。例如,将标识符00112233445566778899aabbccddeeff与客户端/用户#相关联的数据库表1337
  3. 让客户端在所有后续请求中重新发送在(1.)发送给它的标识符,无论是在HTTPCookie请求标头中还是?sid=00112233445566778899aabbccddeeffparam(*)。
  4. 使用(2.)的机制查找接收到的标识符,检查是否有效的身份验证,并被授权执行请求的操作,然后代表已认证的用户继续进行该操作。

当然,您可以在现有基础架构上构建,可以在应用程序中使用PHP的会话管理(将处理1./2。和4.的身份验证部分),并要求客户端实现进行cookie管理(即将处理3.),然后在此基础上执行其余应用逻辑。


(*)每种方法都有优点和缺点,例如,使用GET请求参数更易于实现,但由于记录了GET请求,因此可能会带来安全隐患。您应将HTTPS用于关键(全部?)应用程序。


2
完美答案!谢谢
苛刻达塔尼

为了向任何读者添加更多信息,会话管理最重要的方面之一就是安全性。这样做有很多方面:使用什么类型的令牌,撤销的工作方式,令牌的长度和熵以及防范各种攻击。另外,如果令牌确实被盗(理论上总是可能的),我们如何检测到这种活动(请参阅RFC 6819中的旋转刷新令牌)?由于我无法在本评论部分中解释我的所有想法,因此您可以在此处阅读有关此主题的更多信息:medium.com/@supertokens.io/ee5245e6bdad
Poddar

47

会话管理是服务器的责任。创建会话时,将生成会话令牌并将其发送到客户端(并存储在cookie中)。之后,在客户端和服务器之间的下一个请求中,客户端通常将令牌作为HTTP cookie发送。所有会话数据都存储在服务器上,客户端仅存储令牌。例如,要在PHP中启动会话,您只需:

session_start();  // Will create a cookie named PHPSESSID with the session token

创建会话后,您可以在其上保存数据。例如,如果要保持用户登录状态:

// If username and password match, you can just save the user id on the session
$_SESSION['userID'] = 123;

现在,您可以检查用户是否已通过身份验证:

if ($_SESSION['userID'])
    echo 'user is authenticated';
else
    echo 'user isn't authenticated';       

如果需要,可以仅为经过身份验证的用户创建会话:

if (verifyAccountInformation($user,$pass)){ // Check user credentials
    // Will create a cookie named PHPSESSID with the session token
    session_start();
    $_SESSION['userID'] = 123;
}

9

对于Web应用程序和API而言,有多种方式可以供真实用户使用。有几个标准,或者您可以编写自己的自定义授权/和/或身份验证。我想指出授权和身份验证之间的区别。首先,应用程序需要验证请求来自的用户(或api客户端)。一旦对用户进行身份验证,则根据用户的身份,应用程序需要确定任何经过身份验证的用户都有权执行某些应用程序(授权)。对于大多数传统的Web应用程序而言,安全性模型没有很好的粒度,因此一旦对用户进行身份验证,在大多数情况下,它也有权执行某些操作。但是,这两个概念(身份验证和授权)应作为两个不同的逻辑操作。

此外,在传统的Web应用程序中,在对用户进行身份验证和授权后(通常通过在数据库中查找用户名/密码对),将授权和身份信息写入会话存储中。会话存储不必一定是服务器端,如上面的大多数答案所示,它也可以存储在客户端的cookie中,在大多数情况下都是加密的。例如,PHP CodeIgniter框架默认情况下会执行此操作。有很多机制可以在客户端保护会话,并且我看不到这种存储会话数据的方式要比存储sessionId安全性低,后者随后在服务器端的会话存储中进行了查找。此外,在分布式环境中存储会话客户端非常方便,

此外,在所有情况下都不必通过自定义代码进行简单的用户密码对进行身份验证,该自定义代码在数据库中查找匹配的用户记录。例如,有基本身份验证协议摘要身份验证。在诸如Windows平台之类的专有软件上,也存在验证用户访问权限的方法,例如ActiveDirectory

提供用户名/密码对不仅是身份验证的方式,如果使用HTTPS协议,还可以考虑使用数字证书进行身份验证。

在特定的用例中,如果设计使用SOAP作为协议的Web服务,那么还会有针对SOAP协议的WS-Security扩展。

综上所述,我要说的是,对以下问题的答案进入用于选择WebApi授权/身份验证机制的决策程序:

1)目标受众是什么,它是公开可用的,还是仅针对注册(付费)成员?
2)它运行还是* NIX或MS平台
3)预期用户数量
4)处理多少敏感数据API(强或弱认证机制)
5)您可以使用任何SSO服务

.. 还有很多。

希望这能使事情一点点清除,因为方程中有很多变量。


1

如果基于API的APP是客户端,则API必须具有从服务器响应流中检索/读取Cookie并将其存储的选项。用于在为同一服务器/ URL准备请求对象时自动附加cookie。如果不可用,则无法检索会话ID。


1

没错,在标准环境中事情是“自动的”是因为Cookie比URL传播更受青睐,以使用户保持美观。也就是说,浏览器(客户端软件)管理与每个请求一起存储和发送会话cookie。

在API领域,简单的系统通常只是随每个请求一起传递身份验证凭据(至少在我的工作范围内)。客户作者通常(再次以我的经验)不愿实现cookie存储,并随每个请求进行传输,并且通常不超过最低要求。

对于基于HTTP的API,还有很多其他身份验证机制,HTTP基本/摘要仅举几例,当然,无处不在的o-auth是专门为这些事情而设计的,如果我没有记错的话。不保留任何cookie,凭据是每次交换的一部分(对此非常确定)。

要考虑的另一件事是您要使用API​​在服务器上进行会话。网站上的会话为当前用户提供存储,并且通常存储少量数据以减轻页面之间的数据库负载。在API上下文中,这几乎是没有必要的,因为事情基本上是无状态的。这实际上取决于服务在做什么。


1

我建议您随每个请求发送某种令牌。

取决于服务器和服务,这些可以是GET / POST请求中的JSESSIONID参数,也可以是Web Service请求中基于SOAP over HTTP的SAML之类的成熟参数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.