iOS 6 injecting should_group_accessibility_children to POST requests
October 3, 2012 § 5 Comments
After iOS 6 dropped, we got reports that an iPhone app of ours had stopped working after upgrading. We quickly confirmed that this was indeed the case and started to investigate.
To set the scene here, this is a native iOS app, which speaks to a Rails based API. Initially we thought that this might be related to the reported ‘iOS 6 breaks POST requests’ issue, but after some investigation it became apparent that form fields from any POST reqs were getting the param should_group_accessibility_children (or shouldGroupAccessibilityChildren) injected into them.
When this extra param hits the API and we call something such as:
@user = User.new(params[:user])
@user.save
Rails will throw an exception as the User model is not aware of the should_group_accessibility_children attribute. This will in turn return a 500 to the iOS client, which will display an error to the user.
For a quick fix, we monkey-patched AR::Base to add this attribute and subsequently ignore it. This worked fine, but just didn’t feel right. We then decided to see if it was possible to parse out these params using middleware, which indeed it is.
We have since released rack-remove-param, which can be used to solve exactly this. It’s actually a little more general however, you can use it to filter out any params you might not want hitting your application.
To use, simply add the gem to your Gemfile and then the following to your application.rb:
config.middleware.insert 'Rack::RemoveParam', 'should_group_accessibility_children'
There doesn’t seem to be much info out there on what this param is (why you would add unknown form fields to reqs is another question!), but it seems to be related to some new accessibility features. If anyone has more info, then please comment.
Update
Ok, so thanks to some comments and further discussion internally we can offer some answers to this.
iOS6 does not inject this param to POST requests. iOS has for some time added properties related to accessibility to base objects. The problem here is how we serialise them to JSON, which currently maintains a blacklist of attributes we don’t want. Obviously when iOS adds a new accessibility attribute it will get added to the JSON. A much better approach (and the one we would always prefer), is to maintain a whitelist of attributes to serialise.
There have also been comments on HN relating to the fact that there is no need for this middleware if you are properly protecting against mass-assignment. Whilst this is true in part, a fairly normal behaviour when you receive a param you don’t want to mass-assign is to raise an error, which would result in the same behaviour in the client (i.e broken). Therefore it can be useful to filter the param via middleware whilst clients are updated.
Its maybe worth mentioning that the API already did filter out harmful params (i.e. things that could exploit the rails mass-assignment), and would raise errors on unexpected ones. Therefore a new parameter coming from a client would stop the client from successfully creating an object.
iOS 6 doesn’t do this. If you think it does, then reproduce it with a minimal test case. I have inspected some iOS 6 POST requests, and haven’t seen anything like this.
Hi John, yes you’re correct here – I’m just about to update the post, but it is the way the app is serialising an object into JSON. iOS has for a while injected properties into objects for accessibility which we normally filter before serialising, however the new ones added in iOS6 weren’t. A better approach here would be to only serialise specific attributes, rather than filtering.
forcing params to match a model is stupid rails should just have an option to not do that
You’re basically telling that your Rails application is vulnerable for mass assignment attacks.
No, as mentioned in the update we’re filtering out unwanted attributes. Its worth noting that the example given is not from the code…it was purely to illustrate.