【问题标题】:Patterns for JavaScript security with back-end authorization?具有后端授权的 JavaScript 安全模式?
【发布时间】:2011-11-15 16:57:43
【问题描述】:

我正在寻找一些关于如何在客户端 JavaScript 中处理基本安全需求(例如授权)的良好资源、模式和实践。

我正在构建一个带有后端系统的网站,该系统运行一个常见的 MVC 框架。后端将处理所有真正的安全需求:授权和身份验证。前端将使用 Backbone.js、jQuery 和其他一些库构建,以提供非常丰富的用户体验。

这是我需要处理的一种场景的示例:

我有一个数据网格,上面有几个按钮。如果您在网格中选择一个项目,某些按钮将启用,因此您可以对所选项目执行该操作。这个功能很容易构建......

现在我需要考虑授权。后端服务器将只呈现允许用户使用的按钮。此外,当用户尝试执行该操作时,后端服务器将检查授权。 ...因此后端被覆盖,如果未经授权,用户将无法执行他们尝试的操作。

但是 JavaScript 呢?如果我的代码设置了一堆 jQuery 单击处理程序或其他启用和禁用按钮的事件,我如何处理不存在的按钮?我只是写一堆丑陋的if 语句来检查按钮的存在吗?或者我是否以某种方式编写 JavaScript,只允许我根据授权将现有按钮的 JavaScript 发送到浏览器?还是???

现在想象一个树视图,它可能允许也可能不允许拖放功能,基于授权......以及一个添加/编辑表单,可能基于授权存在或可能不存在......以及所有其他复杂的授权需求,使用大量 JavaScript 来运行这些前端。

我正在寻找资源、模式和实践来处理这类场景,其中后端处理真正的授权,但前端还需要根据授权来解决不存在的事情。

【问题讨论】:

  • 投票迁移 - 这个论坛更多地处理具体的代码问题/解决方案,而不是扩展讨论比较方法。 FWIW,Javascript 本质上是不安全的,因为它在客户端计算机上运行。它可以用来补充后端安全性,但永远不应该被依赖作为它的替代品。
  • 一般你模块化特征检测。这个想法是每个页面都有一个它需要的可能模块列表,每个模块检查 DOM 是否真的需要它。因此,您所有的按钮都变成了模块。通过使用为您执行此模块化加载的模板引擎,这将大大改善
  • 哪些 StackExchange 站点更适合此操作?
  • @DerickBailey 最合适的是 StackOverflow

标签: javascript security authorization backbone.js design-patterns


【解决方案1】:

我可以看到三个相当简单的事情:

  • 模块化主干视图 我变得非常喜欢嵌套和高度模块化的 Backbone 视图。也就是说,树中的每一行都可以是一个 Backbone 视图,并对它们自己的授权要求做出反应。

  • 多个事件哈希根据您的授权要求并由事件触发,在您使用 delegateEvents() 切换的视图上设置多个事件哈希。这样你就可以绕过一组丑陋的 if 语句。

  • 多个模板与此类似,您可以根据授权要求指定要呈现的多个模板。

所有这三个都需要一个已设置的事件结构(例如,使用您自己的 vent PubSub 处理程序),您可以在其中根据 RESTful 服务器请求的响应或基于某些客户端功能触发授权检查。

【讨论】:

  • 我还发现,对于一些简单的差异,您可以使用 css 来实现。向 添加一些类或 data-logged-in="true" ,然后根据它显示/隐藏您需要的内容。
【解决方案2】:

我在客户端处理身份验证的方式是拥有一个单例 Backbone 模型,该模型包含一个 isAuthenticated 值,我最初从服务器填充该值:

@{
  App.user.set({ isAuthenticated: @UserSession.IsAuthenticated.ToString().ToLower() });
}

然后所有基于身份验证更改行为的 javascript 控件/功能基本上只是侦听此字段的更改并将自己重新呈现到正确的状态。所有这些视图/逻辑都是使用 JavaScript 完成的,因此它可以在页面生成时(由服务器)或使用 Javascript/ajax 在客户端上工作。

我不维护现有/隐藏功能的事件处理程序,我重新创建所有 UI 元素并在基于 isAuthenticated 标志重新呈现视图后重新连接所有事件处理程序。

好消息是,一旦您在客户端使用 ajax 登录(即在呈现服务器页面之后),您只需要设置相同的字段,就好像魔术一样(Backbone FTW :) 它一切正常并正确呈现.

【讨论】:

    【解决方案3】:

    客户端的任何东西都可能被黑客入侵。因此,我们在单页 js 应用程序中所做的是服务器上的权利。我们结合了每个用户的权利列表,并有一个 OAuth 令牌,我们将其传递给客户端并与每个请求一起发回。然后在服务器端执行操作之前,我们会查看用户是否已通过此操作的身份验证。

    当然,这并不能保护您免受咖啡馆里有火羊的人的伤害……但这是另一个问题。

    【讨论】:

    • 哦,代替 if 语句的替代方法是在服务器端生成一个对象字面量,这是一个可以与策略模式结合使用的表。这样你就不会到处写了。
    【解决方案4】:

    我建议使用工厂模式和 Backbone 的类属性来根据用户的授权来初始化不同的视图。在下面的示例中,我定义了一个包含所有默认和常见行为的基本 GridView。 AdminGridView 和 EditorGridView 包含授权用户的特定功能。在下面的简化示例中,点击处理程序只会为管理员连接。

    好处是所有东西都被封装了,所以只有工厂需要知道 AdminGridView 和 EditorGridView。您的代码只会与 GridView 交互。

    // GridView is an abstract class and should not be invoked directly 
    var GridView = Backbone.View.extend({ 
    
        // put all common / default code here
    
        _template: _.template($('#grid').html()),
    
        initialize: function(){
            this.model.bind('change', this.render, this);
        }.
    
        onButtonClick: function(){
            // do something
        },
    
        render: function(){ 
            $(this.el).html(this._template(this.model));
        } 
    }, { 
    
        create: function (options) { 
            switch (options.authorization.get('type')) { 
                case 'admin': 
                    return new AdminGridView(options); 
                case 'editor': 
                    return new EditorGridView(options); 
                default:
                    throw new Error('Authorization type ' + options.authorization.get('type') + ' not supported.'); 
            } 
        } 
    }); 
    
    var AdminGridView = GridView.extend({
        // put admin specific code here
        events: {
            'click .button': 'onButtonClick'
        }
    }); 
    
    var EditorGridView = GridView.extend({
        // put editor specific code here
    });
    
    var authorization = new Backbone.Model({ type: 'admin' });
    var gridView = GridView.create({ model: someModel, authorization: authorization });
    $('body').append((gridView.render().el))
    

    【讨论】:

      【解决方案5】:

      既然你提到骨干,你的代码不应该是

      一堆 jQuery 点击处理程序

      但是您可以使用模型来存储有关授权的数据并让您的视图做出相应的反应。

      【讨论】:

      • +1... 我只是想以一种更容易让非骨干人员参与进来的方式来描述问题。
      【解决方案6】:

      我们处理这个问题的方式是让服务器向我们发送需要根据导致结果的一个或多个决定呈现的 html。像这样的

      this.ActionFor(Model)
                      .Decision<Authentication1>()
                      .Decision<Authentication2>()
                      .Consequence<HTMLRenderer>()
      

      如果您认为需要,您可以在 JS 中类似地使用这种模式。

      【讨论】:

      • 对 - 我在描述中指出,服务器只呈现用户可以做的事情。你如何在javascript中处理这个?
      • 我们在选择一行发送实体的ID时,我们会发现事件,然后服务器可以决定渲染或更呈现哪个按钮或按钮,如onRowSelected: function (e, ui) { $('#entity-placeholder').load('/entity/manage/' + ui.data.Id, function () { //callback }); } span>
      【解决方案7】:

      在客户端,让 JQuery 处理它。如果元素不存在,它不会做任何事情。它只将事件处理程序附加到它找到的那些元素上,您不需要任何if-an-element-exist 检查,只需使用 JQuery 选择器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 2012-12-27
        • 2019-03-09
        • 2015-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多