MarkUs Blog

MarkUs Developers Blog About Their Project

Archive for June, 2014

Carpentry in React

without comments

React is a JavaScript library for building user interfaces. It’s used heavily in production in both Facebook and Instagram (Facebook created React), and in my opinion is an awesome tool for building front-end interfaces.

The work I’m currently doing on MarkUs involves re-implementing, using React, the sortable, searchable, and filterable tables used for listing users and managing groups, graders, and submissions. This is a prime target because 1) the previous tables used a library that depended on Prototype, which we are trying to move away from, 2) these tables can be really slow, since the html for each row is rendered in the backend individually, and 3) the previous tables became messy enough (_boot.js.erb files and construct_xxx_table_row methods) to warrant a rewrite. Also because 4) React is awesome. So let’s go into how React works.

React, at its core, is a library for creating components: functional, reusable, and composable web views. It also manages to let you do this in an extremely simple fashion.

Each component has two objects: this.props and this.state. Props are generally for holding immutable data, while state holds mutable data. In a sortable table, for example, the titles of the columns would go into props and the currently sorted column and sort direction would go into the state. A component then defines a render method that is functionally pure; that is, given the same props and state, the output will always be the same. The render method also cannot cause any side effects.

Now, when React detects a state change of any kind, it’ll quickly re-render diffs for the new DOM based on the render method. Managing state suddenly got a lot easier.

Here’s an example from MarkUs: StudentsTable, which is the React component that defines the listing of students in the Users view. StudentsTable has two pieces of state: students, which is the array of student data that will be used to fill the table, and selected_students, which is an array of student ids that represent the selected students (duh) for doing actions on.

The render method then defines some column and filter objects (based on an ad hoc protocol; column objects have boolean attributes such as sortable and searchable while filter objects define a test for each object). Then it returns a div (really a React DOM object: React uses a virtual DOM) containing two other components: an ActionBox and a Table.

Here’s some demo code for StudentsTable:

StudentsTable = React.createClass({
  getInitialState: function() {
  // Sets this.state.students to
  // what the backend returns
  jQuery.ajax({
    method: 'GET',
    url: ...
    dataType: ...
    success: ...
    });
  },
  render: function() {
    // this stuff could and maybe should actually be moved to props
    var columns = [
      { id: "user_name", sortable: true, searchable: true },
      { id: "first_name" , sortable: true, searchable: true }
      ...
    ];
    var filters = [
      { name: 'all', func: function(student) { return student; } },
      { name: 'active', func: function(student) { return student.active; } },
      ...
    ];
    return (
      <div>
        <StudentsActionBox selected_students={this.state.selected_students}
                           onChange={this.refresh} />
        <Table data={this.state.students} columns={columns} filters={filters} />
      </div>
    }
});

Now, StudentsTable will pass down selected_students to ActionBox, which will receive it as props. This may be a little confusing since selected_students was in state originally, but it doesn’t matter. ActionBox doesn’t know, and ActionBox doesn’t care. Its render function should account for both state and props, and in fact it helps to think of selected_students as immutable, since what ActionBox really needs to be worrying about are things like the dropdowns and the grace credits input and managing that stuff.

We can see that the data flow is kept one-way: StudentsTable, as the parent of the ActionBox, doesn’t know about the state of the ActionBox, nor does it care. If you really needed to know something, like when StudentsTable should request new data, you can create a hook by passing down the refresh method as a prop and have ActionBox call it whenever it needs to. But in general, it’s best to keep upward data flow as minimal as possible.

The base Table is its own component with its own subcomponents like TableFilter, TableSearch, and TableHeader which may or may not have their own subcomponents. But these parts all work in the same way; they’re just smaller parts. This way, React makes reasoning about a specific level in the view hierarchy a lot simpler since everything is compartmentalized and data flows only one way. Consider implementing the same thing in jQuery or Prototype: it would probably require a crazy amount of reasoning about state (of which the size is huge — blame combinatorial explosion) and DOM manipulation.

In conclusion: React is dope. Its power comes from its means of combination and abstraction (sup Sussman). Check it out here.

Written by Lawrence Wu

June 16th, 2014 at 10:25 am

Posted in Uncategorized

Rails 4 Strong Parameters

with one comment

A long time ago the developers of Rails wanted a simple API for creating new instances of model objects. What they came up looks something like this:

User.new({ user_name: ‘markus’, last_name: ‘Us’, first_name: ‘Mark’, grace_credits: 5, section_id: 2, type: ‘Student’ })

 

This form of initialization, with a hash, is referred to as mass assignment. Using a hash as input to the constructor made the initialization process very flexible and it was used for seeding the database and creating mock objects for testing.

The problem with having something as nice as mass assignment is that it ended up being used for everything. It became (too) common for controller code to be written that would initialize an object by taking input straight from web forms:

def create
    # Default attributes: role = TA or role = STUDENT
    # params[:user] is a hash of values passed to the controller
    # by the HTML form with the help of ActiveView::Helper::
    @user = Student.new(params[:user])
    if @user.save
      flash[:success] = I18n.t(‘students.create.success’,
                               :user_name => @user.user_name)
      redirect_to :action => ‘index’ # Redirect
    else
      @sections = Section.all(:order => ‘name’)
      flash[:error] = I18n.t(‘students.create.error’)
      render :new
    end
  end

 

Or, at least you hoped the params were coming from a web form, and that the person filling in the web form didn’t add some extra data you weren’t expecting. In reality, a malicious user could construct their own POST request to the server and create a new user that had administrative powers. This actually happened to Github a couple of years ago.

This kind of exploit is a text book example of incomplete mediation. Checking the validity of user input on the client side does little to make the app secure. An attacker has full control of the client and can manipulate input to the server in any conceivable way. User side checking may be valuable for user experience reasons, but the checks must also be performed again on the server where we have control. More information on the principles of security for protecting computer information can be found here.

Shortly after the Github/Rails issue, the Rails core team wanted safe defaults for new projects. At the time, the existing Rails solution for this issue was to declare model attributes as being mass assignable or not mass assignable. In code, you would declare attributes as attr_accessible (whitelist) or attr_protected (blacklist), and these declarations would be used to maintain a whitelist of attributes which could be set using mass assignment. However, whitelisting was not enabled by default, and so in Rails 3.2.8, all new apps included the following configuration:

config.active_record.whitelist_attributes = true

Which caused all models to start with an empty whitelist. Mass assignable attributes had to be explicitly listed with attr_accessible. Safety by default was implemented, but it came at the cost of being able to use mass assignability for legitimate purposes. The Rails security guide from that era includes more details on the whitelist configuration and how to work with its limitations.

The problem with having all models disallow mass assignability was that programmers would have to go to more trouble to seed databases, generate mock objects, etc. Possibly for this reason, MarkUs never turned on default whitelists.

The logic was that the whitelists would stop incomplete mediation attacks from anywhere that models are created. However, these attacks come from user input, which is first handled (on the server side) by controllers. So, performing sanitization checks in the controller would limit the impact of the whitelists to where it mattered.

During Rails 4 development, the core team removed attr_accessible and the entire mechanism for whitelisting attributes in model classes. The new solution, strong_parameters, enforces attribute whitelists on the input params before passing the data along to the model constructor. Since strong_parameters does not directly affect model code, it is once again easy to use mass assignment for internal machinery and trusted scripts.

MarkUs predates Rails 3.2.8, and the whitelist default was never turned on during the upgrade to Rails 3.2. MarkUs does use attr_accessible in a couple of places, and avoids using mass assignment for input coming from students. However, the example controller code above (that demonstrates the incomplete mediation flaw) comes straight from the MarkUs code base as it exists today. The example is actually fairly safe because it requires an authorized admin to make the POST in the first place, but nonetheless demonstrates unsafe practices.

I think that current strategy for handling student input entirely without mass assignment is the best strategy from a security perspective. This would also make the upgrade to strong_parameters painless.

It is not recommended to switch to strong_parameters and perform the Rails 4 upgrade at the same time. However, strong_parameters is available for Rails 3.2 as a back port and we can migrate to it before the upgrade to Rails 4. I think it would be best to switch to strong_parameters right away and move away from using mass assignment when the input comes from the client side.

A blog post demonstrating how strong_parameters works can can be found here. The API documentation for strong_parameters can be found here.

Written by Mark Rada

June 11th, 2014 at 11:53 am

Posted in Uncategorized