如何在 angularjs 应用程序中实现安全(!)身份验证系统?

Posted

技术标签:

【中文标题】如何在 angularjs 应用程序中实现安全(!)身份验证系统?【英文标题】:How to achieve a Safe (!) authentication system in an angularjs app? 【发布时间】:2013-01-25 07:52:29 【问题描述】:

我是 angularjs 新手...

我阅读了文档,并完成了教程;我自己也尝试了其他东西,事情开始对我有意义。

现在我想知道如何制作一个安全的身份验证系统

简单的部分:没有代码,我将描述我的代码执行的操作:

我有一个经典的表单:用户名和密码文本输入。

用户填写表单,然后按 ENTER。

一个 ajax 请求开始,响应是一个 JSON 告诉我 诸如“好吧,我认识你”或“我不知道你是谁”之类的。

我现在需要的是在我的应用程序的不同视图之间维护访问者的登录状态(或未登录)。

我在网上看到,为了实现这个目标,有人设置了一个变量($scope.isLogged = true),有人使用了 cookie;但是可以使用 firebug 或类似的开发工具轻松编辑 javascript 变量和 cookie。

...最后是问题:

那么,您对在 angularjs 应用中实现安全的身份验证系统有什么建议吗?

【问题讨论】:

【参考方案1】:

首先:客户端数据总是可以被操纵或篡改。

只要有效的会话 ID 不容易被猜到,并且像将会话令牌与客户端的 IP 相关联这样的措施,这没什么大不了的。

理论上,您也可以加密 cookie,只要您在服务器端这样做。

有关如何加密 cookie 的详细信息,请参阅服务器端的文档(例如,http://expressjs.com/api.html#res.cookie 用于 Express.js)

【讨论】:

首先感谢您的回答!按照您的建议进行,每次视图更改时,我都必须执行 ajax 请求以检查存储在变量/cookie 中的会话密钥是否与身份验证时生成的相同......我对吗?还是我错过了一些东西? 基本上,对于每一个需要用户认证的HTTP请求,服务器都会在请求到来时检查会话密钥。如果会话密钥不正确,服务器可以返回一个' 401 not authorized'而不是客户想要的数据。【参考方案2】:

你不能在 angularjs 中授权任何东西,因为用户可以完全控制执行环境(即浏览器)。每张支票,每一个案例,如果——任何你能想到的——都可以被篡改。有一些 javascript 库使用非对称密钥来执行本地加密以在一定程度上安全地存储本地数据,但它们并不是您真正想要的。

你可以而且你应该在服务器上授权——这是你在普通应用程序中执行的标准方式——使用会话;不需要特殊代码,ajax 调用使用普通会话 cookie。应用程序不需要知道它是否经过身份验证。它只需要检查服务器的想法。

从您的 angularjs 应用程序的角度来看,“登录”或“注销”只是用户的 gui 提示。

【讨论】:

+1,特别是对于“从您的 angularjs 应用程序的角度来看,“登录”或“注销”只是用户的 gui 提示。”如果用户想要篡改他们的执行环境,让 Angular 认为他们已经登录,那就这样吧——只要服务器仍然验证任何更改实际数据的操作等。 您好,谢谢。我对你的回答很感兴趣。特别是在你提到会话的部分,因为这是我工作的传统方式......我使用 php 作为服务器端语言......只是另一个问题(我现在没有时间亲自尝试,但我会尽快做[独立于你的回答,我保证:)]):如果在 ajax 请求期间设置一个会话,那么这个会话在下一个请求中仍然可用,对吗? @JamesEmerton:那是因为它与问题完全无关。 CSRF 保护与 angularjs 完全无关。出于同样的原因,我没有提到 SQL 注入、会话固定等——它们没有添加任何特定于角度的东西。 @fdreger 我不同意;问题是关于安全 身份验证系统。人们将 SO 用作学习资源,重要的是至少指出最相关的陷阱。 @JamesEmerton Web 应用程序安全性(包括身份验证及其陷阱)是一个庞大的主题,不可能在一个答案中详细涵盖。 SO 格式并不是要提供最完整的信息。相反:SO 的优势在于对具体问题给出具体答案。相关性是关键。如果您真的说添加有关 CSRF 的内容很重要,那么您为什么不提及正确的密码散列?防止 HTML 注入?反对会话固定?为什么包括 CSRF 而不是 SQL 注入?【参考方案3】:

您可能找到了解决方案,但目前我制定了一个正在我的 Angular 应用程序中实施的身份验证方案。

在 .run 上,应用注册时 ActiveSession 设置为 false。 然后它会检查浏览器是否有一个带有令牌和用户 ID 的 cookie。

如果是,检查服务器上的 token+userId 并更新服务器和本地的令牌(令牌是服务器生成的每个用户唯一的密钥)

如果 NO 显示登录表单,请检查凭据,如果它们有效,服务器会再次请求获取新令牌并保存在本地。

令牌用于进行持久登录(记住我 3 周)或当用户刷新浏览器页面时。

谢谢

【讨论】:

加一个用于认真对待问题,即使它来自您不认识的人【参考方案4】:

我三个月前问过这个问题。

当我必须在基于 AngularJS 构建的网络应用中处理用户身份验证时,我想分享我最喜欢的方法。

当然,fdreger 的回答还是很好的回答!

你不能在 angularjs 中授权任何东西,因为用户有完整的 执行环境(即浏览器)的控制。

从您的 angularjs 应用程序的角度来看,正在“登录” 或“注销”只是用户的 gui 提示。

所以,简而言之,我的方法包括:

1) 为每个路由绑定关于路由本身的附加信息。

$routeProvider.when('/login',  
    templateUrl: 'partials/login.html', controller: 'loginCtrl', isFree: true
);

2) 使用服务来维护有关每个用户的数据及其身份验证状态。

services.factory('User', [function() 
    return 
        isLogged: false,
        username: ''
    ;
]);

3) 每次用户尝试访问新路由时,检查他们是否有访问权限。

$root.$on('$routeChangeStart', function(event, currRoute, prevRoute)
    // prevRoute.isFree tell me if this route is available for all the users, or only for registered user.
    // User.isLogged tell me if the user is logged
)

我还在我的博客users authentication with angularjs 上写过这种方法(更详细)。

【讨论】:

【参考方案5】:

你需要了解它的服务器端/数据库端。

用户登录信息需要存储在某个地方 - 99.9% 的时间都存储在服务器端数据库中。

理想情况下,对于真正安全的系统,您需要一个后端(服务器端)成员系统,该系统将会话存储在与包含加密密码的成员表相关的数据库表中,但还提供一个 RESTful 接口,您可以在其中构建你的 api 调用。

我成功使用的一个脚本是成员https://www.amember.com/。尽管还有很多其他脚本,但这是一种非常经济有效的方式,我在这个方面取得了很大的成功。它也是 PHP,所以你可以为你的 Angular http 调用构建一个 API很容易。

所有这些 javascript 框架都很棒,但效果是现在太多人过于关注事物的前端——同时学习数据库/后端! :-)

【讨论】:

以上是关于如何在 angularjs 应用程序中实现安全(!)身份验证系统?的主要内容,如果未能解决你的问题,请参考以下文章

如何在AngularJS中实现带有输入字段的模板组件

如何使用php json数组在带有angularjs的cordova中实现推送通知

如何在 AngularJS 中实现 websockets?

如何在angularjs中实现导航栏

如何在 Web 表单中实现 AngularJS 控制器?

如何在 AngularJS 中实现组件组合(类似于 React 渲染道具模式)?