REST scaffold_resource security warning
Posted by Jim Morris on Tue Jun 26 15:14:04 -0700 2007
This one is so blatantly obvious it bit me in the Butt at 4am this morning when I had to get up and fix it! I am so embarrassed, luckily no private data got out, as no-one has entered any private data yet.
I used the script/generate scaffold_resource to get started, and I left in those nice format.xml things in, thinking I may use them in the future. For the most part this is not a problem, but one of my controllers is a profile table. Much of the data in there is public anyway so no big deal, but a few columns are private data like email, date of birth, phone numbers etc. These are specifically private and not viewable publicly. This is enforced but not having a view that shows any of that stuff to the general public.
However the tricky little scaffold-generated code...
Has this cool .to_xml stanza, which happily takes every column and converts it to XML and sends it back as a response to the query /profiles.xml
Yikes, I woke up with a start when I realized that, and rushed to test it and yep it works as it is supposed to.
Obviously this is easy to fix, Just exclude the attributes you don't want shown:
@profiles.to_xml(:only => [:first_name, :last_name])
But it sure is a nasty back door if you forget!
Caveat Programmer!
Nice catch! Time to go review some code.
Actually, its probably better to fix that in the model, and not the controller.
Using `attr_accessible` or `attr_protected`, or something similar - just close those columns for the general public and all your problems disappear. Besides, its the more "right" place for it anyways.
AFAIK `attr_protected` and `attr_accessible` only protect against mass writes not reads, so that won't work in this case.
Thanks for this -- I had the same realization, and now I can fix it.
The other thing to set is filter_parameter_logging, which controls what goes into your logs. (Logs should of course be outside the public purview, but 'Defense in Depth' is our creed.)
If I understand correctly, attr_accessible controls data coming *in* -- it prevents someone setting an attribute by stuffing in a form value.
Using the the restful-authentication generator as an example:
* In the model file, blacklist fields from the logs:
filter_parameter_logging :password, :salt, "activation-code"
* Also in the model, whitelist fields the user is allowed to set (this excludes things like confirmation code or usergroup):
attr_accessible :login, :email, :password, :password_confirmation
* And, of course, in the controller file whitelist only the fields you wish to xml serialize:
format.xml { render :xml => @user.to_xml(:only => [:first_name, :last_name]) }