Suas aplicações rails são seguras? (scoped queries)

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.

Posted in ,  | Tags ,  | 2 comments

Recuperando informações EXIF com RMagick

Posted by Leonardo Sun, 29 Jul 2007 22:32:41 GMT

Quando tiramos fotos, as câmeras digitais gravam algumas informações no arquivo gerado, como nome do fabricante e modelo da câmera, data em que a foto foi tirada, o ISO selecionado, distância focal, etc.

Com o RMagick, essas informações são acessadas de forma extremamente simples. Na verdade, é possível acessá-las de mais de uma maneira como mostrado abaixo:

def upload
  pic = Magick::Image.from_blob(params[:image].read)[0]
  @taken = pic.get_exif_by_entry('DateTimeOriginal')
  @maker = pic['Exif:Make']
  @model = pic['Exif:Model']
end

A diferença entre as duas formas é que a primeira retorna um array contendo entradas do tipo nome,valor, enquanto que na segunda forma, apenas o valor é retornado.

Posted in  | Tags ,  | no comments

Older posts: 1 2