2

By default, rails 3.2 sets active_record.mass_assignment_sanitizer = :strict in config/environments/development.rb. (See railcasts episode http://railscasts.com/episodes/318-upgrading-to-rails-3-2). Here it is:

# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict  

This makes the mass assignment error-prone in development and force to list every attributes for attr_accessible. What's the reasoning for doing this by default in rails 3.2(haven't checked if it is rails 4 as well)?

user938363
  • 9,990
  • 38
  • 137
  • 303

1 Answers1

2

The link provided by Baldrick seems to be gone now. But I recently read a blog post that gives very useful context on the evolution of the mass assignment security issue in Rails: http://net.tutsplus.com/tutorials/ruby/mass-assignment-rails-and-you/

I'm not an expert on this issue but here's my understanding: Misconfiguring mass assignment in Rails could lead to really, really big security issues, all the more dangerous now that they've been popularized. Rails 4 attempts to patch over the biggest threats by requiring you to explicitly list the fields that can be mass-assigned right in the controller, where security concerns are easy for you to see and handle. But the handling of mass assignment in Rails 3 was more variable, and in many cases, if a parameter was submitted that wasn't on the attr_accessible whitelist (or was on the blacklist), Rails would simply skip over that parameter, without letting the developer know that anything had happened wrong.

This was a problem. If I'm writing an app that demands high security (or, these days, any level of security), if I've written a test to ensure that certain parameters are rejected, I want to know that they're being rejected. I'd much rather find out what Rails is doing sooner rather than later, so that I can adjust my code and plan future site sections accordingly. So, the mass_assignment_sanitizen = :strict setting makes this more vocal behavior the default.

You say that this setting makes mass assignment behavior more "error-prone" in development, as though this were a problem. I would think you would want your Rails app to be as error-prone and as vocal as it can be, during the development and testing phases, so that you learn about more of the potential problems in your code sooner on. So I appreciate the mass_assignment_sanitizer default.

Fortunately for both of us, Rails 4 has simplified this issue by taking a stronger stand in favor of strictness. Strict mass-assignment parameter sanitization, along with its vocal error-prone-ness, has become a default feature of the controller (since this issue never really belonged in the model in the first place) and provides you with a friendly private function where you can define any alternate behavior you need.

Topher Hunt
  • 4,404
  • 2
  • 27
  • 51
  • 3
    I mostly agree, except for the idea that mass-assignment protection doesn't belong in the model. In fact, the model is the right place for this, and Rails 4's approach is a big step backwards. Why? Because the model should be protected no matter which controller the assignment is coming from; also, it's not the controller's job to know what the model should and shouldn't accept. It's the model's job (just as with validations). Putting mass-assignment protection in the controller means scattering it over lots of places in the application, whereas in the model it can be declared only once. – Marnen Laibow-Koser Aug 13 '14 at 19:24
  • I suspect that the reasoning for removing it from the model is a separation of concerns. Models are responsible for data persistence and integrity/validity, not security/permissions. It also pushes the security outwards, so it protects more than just models, but anywhere the parameters get passed (I think). – dzajic Dec 10 '19 at 23:49
  • @dzajic Even that distinction doesn’t really work: data permissions are part of data integrity, which is why they belong in the model. – Marnen Laibow-Koser Jan 13 '20 at 16:47
  • I don't think that's typical, because authorization is a point-in-time event, a process, and data integrity is a permanent state (think foreign keys). Usually you can't tell by looking at data if the state came about with valid permissions or not, because permissions can change over time. Maybe if there's a super detailed audit trail it would be possible, but I've never worked on such a system in 13 years of working with Rails. – dzajic Jan 14 '20 at 17:48
  • @dzajic Sure, it’s the controller’s job to handle authorization in general, but it’s the model’s job to say “given that the controller tells me that the user is of this class, these are the changes I will accept”. The fact that most systems don’t have a proper audit trail really doesn’t change this. – Marnen Laibow-Koser Feb 25 '20 at 13:10
  • You could do that, it may work at the beginning, but I would favor creating a logical separation between persistence and authorization early on, if not immediately, to ensure the complexity doesn't get out of hand. In my experience it's easier to work with a system where they are orthogonal. Mixing them together tends to evolve into code that's difficult to work with. That doesn't mean it's always better, it's possible to make a mess of anything, but I think it's more likely to succeed because of the separation of concerns. – dzajic Feb 26 '20 at 14:38
  • @dzajic You’re proving my point. User authorization within the application’s logic flow is a controller concern; how that translates into what model changes are allowed (which is not necessarily a persistence issue, because models aren’t primarily about persistence!) is the model’s concern. If you do it otherwise, the controller has to know too much about the model’s implementation. I prefer to keep things orthogonal, so I prefer to keep the model’s implementation in the model. That’s easier to work with and more maintainable. – Marnen Laibow-Koser May 02 '20 at 17:30