简体   繁体   English

使用后端授权的JavaScript安全模式?

[英]Patterns for JavaScript security with back-end authorization?

I'm looking for some good resources, patterns and practices on how to handle basic security needs, such as authorization, in client side JavaScript. 我正在寻找一些关于如何在客户端JavaScript中处理基本安全需求(例如授权)的良好资源,模式和实践。

I'm building a website with a back-end system running one of the common MVC frameworks. 我正在建立一个网站,其后端系统运行一个常见的MVC框架。 The back-end will handle all of the real security needs: authorization and authentication. 后端将处理所有真正的安全需求:授权和身份验证。 The front is going to be built with Backbone.js, jQuery and a few other libraries to facilitate a very rich user experience. 前端将使用Backbone.js,jQuery和一些其他库构建,以提供非常丰富的用户体验。

Here's an example of one scenario I need to handle: 这是我需要处理的一个场景的示例:

I have a grid of data with a few buttons on top of it. 我有一个数据网格,顶部有几个按钮。 If you select an item in the grid, certain buttons become enabled so you can take that action on the selected item. 如果选择网格中的某个项目,则会启用某些按钮,以便您可以对所选项目执行该操作。 This functionality is easy to build... 这个功能很容易构建......

Now I need to consider authorization. 现在我需要考虑授权。 The back-end server will only render the buttons that the user is allowed to work with. 后端服务器将仅呈现允许用户使用的按钮。 Additionally, the back-end server will check authorization when the user tries to take that action. 此外,后端服务器将在用户尝试执行该操作时检查授权。 ... so the back end is covered and the user won't be able to do what they try, if they are not authorized. ...所以如果未经授权,后端将被覆盖,用户将无法执行他们尝试的操作。

But what about the JavaScript? 但是JavaScript怎么样? If my code is set up with a bunch of jQuery click handlers or other events that enable and disable buttons, how do I handle the buttons not being there? 如果我的代码设置了一堆jQuery点击处理程序或启用和禁用按钮的其他事件,我该如何处理不存在的按钮? Do I just write a bunch of ugly if statements checking for the existence of the button? 我只是写了一堆丑陋的if语句来检查按钮的存在吗? Or do I write the JavaScript in a way that lets me only send the JavaScript for the buttons that exist, down to the browser, based on authorization? 或者我是否以一种允许我只根据授权将存在的按钮的JavaScript发送到浏览器的方式来编写JavaScript? or ??? 要么 ???

Now imagine a tree view that may or may not allow drag & drop functionality, based on authorization... and an add/edit form that may or may not exist based on authorization... and all those other complicated authorization needs, with a lot of JavaScript to run those pieces of the front end. 现在想象一下树视图可能允许也可能不允许基于授权的拖放功能......以及基于授权可能存在或不存在的添加/编辑表单......以及所有其他复杂的授权需求,很多JavaScript来运行前端的那些部分。

I'm looking for resources, patterns and practices to handle these kinds of scenarios, where the back end handles the real authorization but the front end also needs to account for things not being there based on the authorization. 我正在寻找资源,模式和实践来处理这些类型的场景,其中后端处理真正的授权,但前端还需要考虑基于授权的不存在的事情。

There are three fairly straightforward things I could see: 我可以看到三件相当简单的事情:

  • Modular Backbone Views I grew very fond of nested and highly modular Backbone views. 模块化骨干视图我非常喜欢嵌套和高度模块化的Backbone视图。 That is, every row in your tree could be a Backbone view and reacting to their own authorization requirements. 也就是说,树中的每一行都可以是Backbone视图,并根据自己的授权要求做出反应。

  • Multiple Event Hashes Set up multiple event hashes on the view that you switch out with delegateEvents() based on your authorization requirements and triggered by an event. 多事件哈希建立在你切换出根据您的授权要求和由事件触发delegateEvents()视图多个事件哈希值。 That way you get around a set of ugly if statements. 这样你可以绕过一组丑陋的if语句。

  • Multiple Templates In a similar vein, you specify multiple templates to render based on the authorization requirements. 多个模板与此类似,您可以根据授权要求指定要呈现的多个模板。

All three would require an event structure that's setup (for example using your own vent PubSub handler) where you trigger authorization checks based on the response of a RESTful server request, or based on some client-side function. 所有这三个需要一个事件结构的设置(例如,使用你自己的vent ,你触发基于REST风格的服务器请求的响应授权检查PubSub的处理程序),或基于一些客户端功能。

The way I handle authentication on the client is to have a singleton Backbone model that holds an isAuthenticated value that I initially populate from the server with: 我在客户端上处理身份验证的方式是使用单一的Backbone模型,该模型包含我最初从服务器填充的isAuthenticated值:

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

Then all javascript controls/functionality that change behavior based on Authentication basically just listen to changes on this field and re-renders themselves into the correct state. 然后,所有基于身份验证更改行为的javascript控件/功能基本上只是监听此字段的更改并重新呈现为正确的状态。 All this view/logic is done with JavaScript so it works at page generation time (by the server) or on the client with Javascript/ajax. 所有这些视图/逻辑都是用JavaScript完成的,因此它可以在页面生成时(由服务器)或在客户端上使用Javascript / ajax。

I don't maintain event handlers to existing/hidden functionality, I re-create all the UI elements and re-hook up all the event handlers after the views are re-rendered based on the isAuthenticated flag. 我不维护现有/隐藏功能的事件处理程序,我重新创建所有UI元素,并在根据isAuthenticated标志重新呈现视图后重新挂接所有事件处理程序。

The nice thing is that once you login with ajax on the client (ie after the server page has been rendered) you just need to set the same field and as if by magic (Backbone FTW :) it all works and renders correctly. 好的一点是,一旦你在客户端上使用ajax登录(即在渲染服务器页面之后),你只需要设置相同的字段,就像魔术(Backbone FTW :)一样,它都能正常工作和渲染。

Anything on the client side can be hacked. 客户端的任何内容都可能被黑客入侵。 So what we're doing in our singlepage js app is entitlements on the server. 所以我们在单页js应用程序中所做的就是服务器上的权利。 We combine a list of entitlements per user and have an OAuth token that we pass to the client and is sent back with each request. 我们合并了每个用户的权利列表,并拥有一个OAuth令牌,我们将其传递给客户端,并随每个请求一起发回。 then in the server side before an action is taken we see if the user is authenticated for this action. 然后在执行操作之前在服务器端,我们查看用户是否已对此操作进行身份验证。

Of course, this doesn't protect you from someone at a cafe with firesheep...but thats another problem. 当然,这并不能保护你免受火灾咖啡馆里的人的攻击......但那是另一个问题。

I would recommend using the Factory pattern together with Backbone's class properties to initialize different views depending on the authorization of the user. 我建议将Factory模式与Backbone的类属性一起使用,以根据用户的授权初始化不同的视图。 In the example below, I define a base GridView which contains all of the default and common behaviors. 在下面的示例中,我定义了一个包含所有默认和常见行为的基本GridView。 AdminGridView and EditorGridView contains the authorized user's specific functionality. AdminGridView和EditorGridView包含授权用户的特定功能。 In the simplified example below, a click handler will only be wired up for admins. 在下面的简化示例中,只有管理员才会连接点击处理程序。

The nice thing is that everything is encapsulated so that only the Factory needs to know about AdminGridView and EditorGridView. 好消息是所有内容都被封装,因此只有Factory需要知道AdminGridView和EditorGridView。 Your code would just interact with GridView. 您的代码只会与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))

Since you mentioned backbone, your code should not be 既然你提到了骨干,你的代码就不应该

a bunch of jQuery click handlers 一堆jQuery点击处理程序

but instead you can use models to store data about authorization and have your views react accordingly. 但您可以使用模型存储有关授权的数据,并让您的观点做出相应的反应。

The way we handle this is letting the server send us the html that needs to be rendered based on the the decision or decisions that result in a consequence. 我们处理此问题的方法是让服务器根据导致结果的决策或决策向我们发送需要呈现的html。 something like this 这样的事情

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

You could probably use this pattern similarly in JS if you think you needed to. 如果您认为需要,可以在JS中类似地使用此模式。

On client side, let JQuery take care of it. 在客户端,让JQuery来处理它。 If the element is not there, it does not do anything. 如果元素不存在,则不执行任何操作。 It only attaches event handlers to those elements that it finds, you will not need any if-an-element-exist check, just use the JQuery selectors. 它只将事件处理程序附加到它找到的那些元素,你不需要任何if-an-element-exist检查,只需使用JQuery选择器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM