Posted by Leonardo Tue, 31 Jul 2007 21:46:51 GMT
É verdade que utilizando todas as facilidades que o rails nos oferece, conseguimos criar aplicações de forma muito rápida. Isso é ótimo, mas às vezes, criamos uma aplicação tão rapidamente, que ou esquecemos de olhar alguns aspectos de segurança ou não sabemos o que acontece por debaixo dos panos e aí deixamos a aplicação exposta achando que tudo está funcionando redondo.
Vou escrever uma série de artigos mostrando alguns pontos que merecem uma certa atenção quando desenvolvemos nossas aplicações em ruby on rails.
Queries restritas ou scoped queries
Aplicações rails costumam usar IDs de registros nas urls, como por exemplo /contacts/show/28 ou para ser RESTful /contacts/28. Se tivéssemos construído nossa aplicação assim:
class User < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :user
end
Os models são bem simples. Agora o controller:
class ContactsController < ApplicationController
before_filter :require_signin
def new
@contact = Contact.new
end
def create
contact = Contact.new params[:contact]
contact.user_id = session[:user_id]
contact.save
redirect_to contact_url(contact)
end
def show
@contact = Contact.find params[:id]
end
private
def require_signin
return false unless session[:user_id]
end
end
Consegue ver o problema? Ele está no action show. Ainda não viu? Repare que, qualquer pessoa, estando logada no sistema, pode ver qualquer contato. Mesmo que o contato não pertença a ela. Simplesmente acessando uma url /contacts/show/id, passando o id que eu quiser, verei o contato em questão.
Para resolver isso, podemos fazer uma query com escopo definido. Como fazemos isso? Veja abaixo as modificações:
class ContactsController < ApplicationController
# criamos o objeto @current_user
before_filter :require_signin
# safely looks up the contact
before_filter :find_contact,
:except => [ :index, :new, :create ]
def index
@contacts = @current_user.contacts.find :all
end
def new
@contact = @current_user.contacts.new
end
def create
@current_user.contacts.create params[:contact]
redirect_to contacts_url
end
def show
end
def edit
end
def update
@contact.update_attributes params[:contact]
redirect_to contact_url
end
def destroy
@contact.destroy
redirect_to contacts_url
end
private
def require_signin
@current_user = User.find session[:user_id]
redirect_to(home_url) and return false
unless @current_user
end
def find_contact
@contact = @current_user.contacts.find params[:id]
end
end
Veja que agora, não acessamos mais o model Contact diretamente. Todas as consultas ficam restritas ao usuário logado no sistema e assim, apenas os contatos dele estarão visíveis.
O próximo artigo falará de mass assignment. Fiquem ligados.
