Pergunta

Aqui está um exemplo perfeito do problema: Gema classificadora quebra Rails.

** Pergunta original:**

Uma coisa que me preocupa como profissional de segurança é que Ruby não tem paralelo com a privacidade de pacotes do Java.Ou seja, isso não é Ruby válido:

public module Foo
  public module Bar
    # factory method for new Bar implementations
    def self.new(...)
      SimpleBarImplementation.new(...)
    end
    def baz
      raise NotImplementedError.new('Implementing Classes MUST redefine #baz')
    end
  end

  private class SimpleBarImplementation
    include Bar
    def baz
      ...
    end
  end
end

Seria muito bom poder evitar a correção de Foo::BarImpl.Dessa forma, quem depende da biblioteca sabe que ninguém mexeu nela.Imagine se alguém mudasse a implementação do MD5 ou SHA1 em você!eu posso ligar freeze nessas classes, mas tenho que fazer isso classe por classe, e outros scripts podem modificá-los antes de terminar de proteger meu aplicativo, se eu não estiver muito cuidado com a ordem de carregamento.

Java fornece muitas outras ferramentas para programação defensiva, muitas das quais não são possíveis em Ruby.(Veja o livro de Josh Bloch para uma boa lista.) Isso é realmente uma preocupação?Devo simplesmente parar de reclamar e usar Ruby para coisas leves e não esperar por soluções "prontas para empresas"?

(E não, as classes principais não são congeladas por padrão em Ruby.Veja abaixo:)

require 'md5'
# => true
MD5.frozen?
# => false
Foi útil?

Solução

Confira Imutável por Garry Dolley.

Você pode impedir a redefinição de métodos individuais.

Outras dicas

Eu não acho que isso seja uma preocupação.

Sim, o mítico “alguém” pode substituir a implementação do MD5 por algo inseguro.Mas para fazer isso, o alguém mítico deve realmente ser capaz de inserir seu código no processo Ruby.E se ele puder fazer isso, provavelmente também poderá injetar seu código em um processo Java e, por exemplo,reescreva o bytecode para a operação MD5.Ou apenas intercepte as teclas pressionadas e não se preocupe em mexer no código de criptografia.

Uma das preocupações típicas é:Estou escrevendo esta biblioteca incrível, que deve ser usada assim:

require 'awesome'
# Do something awesome.

Mas e se alguém usar assim:

require 'evil_cracker_lib_from_russian_pr0n_site'
# Overrides crypto functions and sends all data to mafia
require 'awesome'
# Now everything is insecure because awesome lib uses 
# cracker lib instead of builtin

E a solução simples é:não faça isso!Eduque seus usuários para que eles não devem executar códigos não confiáveis ​​baixados de fontes obscuras em seus aplicativos críticos de segurança.E se o fizerem, provavelmente merecem.

Voltando ao seu exemplo Java:é verdade que em Java você pode fazer seu código criptográfico private e final e o que não.Contudo, alguém pode ainda substitua sua implementação de criptografia!Na verdade, alguém realmente fez:muitas implementações Java de código aberto usam OpenSSL para implementar suas rotinas criptográficas.E, como você provavelmente sabe, o Debian foi lançado com uma versão quebrada e insegura do OpenSSL durante anos.Então, todos os programas Java rodando no Debian nos últimos anos, na verdade fez corra com criptografia insegura!

Java fornece muitas outras ferramentas para programação defensiva

Inicialmente pensei que você estava falando sobre programação defensiva normal, em que a idéia é defender o programa (ou seu subconjunto ou sua função única) da entrada de dados inválidos.
Isso é ótimo e encorajo todos a lerem esse artigo.

No entanto, parece que você está realmente falando sobre "defender seu código de outros programadores".

Na minha opinião, este é um objetivo completamente inútil, pois não importa o que você faça, um programador mal-intencionado sempre poderá executar seu programa sob um depurador, ou usar injeção de dll ou qualquer outra técnica.

Se você está apenas procurando proteger seu código de colegas de trabalho incompetentes, isso é ridículo. Eduque seus colegas de trabalho ou consiga colegas de trabalho melhores.

De qualquer forma, se essas coisas são de grande preocupação para você, Ruby não é a linguagem de programação para você.Monkeypatching está lá por design, e proibi-lo vai contra todo o objetivo do recurso.

Acho que Ruby tem esse recurso - mais valorizado do que por ser um problema de segurança.Ducktyping também.
Por exemplo.Posso adicionar meus próprios métodos à classe Ruby String em vez de estendê-la ou envolvê-la.

“Eduque seus colegas de trabalho ou consiga colegas de trabalho melhores” funciona muito bem para uma pequena startup de software e funciona muito bem para grandes empresas como Google e Amazon.É ridículo pensar que todo desenvolvedor humilde contratou alguma pequena aplicação de prontuários médicos em um consultório médico em uma cidade menor.

Não estou dizendo que devemos construir para o mínimo denominador comum, mas temos que ser realistas de que há grande quantidade de programadores medíocres por aí que usarão qualquer biblioteca que faça o trabalho, sem prestar atenção à segurança.Como poderia eles prestam atenção à segurança?Talvez tenha feito uma aula de algoritmos e estruturas de dados.Talvez eles tenham feito um curso de compiladores.É quase certo que eles não fizeram um curso de protocolos de criptografia.Definitivamente, nem todos leram Schneier ou qualquer outro por aí que praticamente precisa ler implorar e implorar até mesmo programadores muito bons devem considerar a segurança ao criar software.

Não estou preocupado com isso:

require 'evil_cracker_lib_from_russian_pr0n_site'
require 'awesome'

Estou preocupado sobre awesome exigindo foobar e fazbot, e foobar exigindo has_gumption, e ...eventualmente, dois deles entram em conflito de uma forma obscura que desfaz um importante aspecto de segurança.

Um importante princípio de segurança é a “defesa em profundidade” – adicionar essas camadas extras de segurança ajuda você a não atirar acidentalmente no próprio pé.Eles não podem impedir isso completamente;Nada pode.Mas eles ajudam.

Se o monkey patching for sua preocupação, você pode usar o módulo Immutable (ou uma função semelhante).

Imutável

Você pode dar uma olhada no projeto "Sandbox" do Why the Lucky Stiff, que você pode usar se estiver preocupado com a execução de código potencialmente inseguro.http://code.whytheluckystiff.net/sandbox/

Um exemplo (TicTacToe online):http://www.elctech.com/blog/safely-exposing-your-app-to-a-ruby-sandbox

Raganwald tem um postagem recente sobre isso.No final, ele constrói o seguinte:

class Module
  def anonymous_module(&block)
   self.send :include, Module.new(&block)
  end
end

class Acronym
  anonymous_module do
    fu = lambda { 'fu' }
    bar = lambda { 'bar' }
    define_method :fubar do
      fu.call + bar.call
    end
  end
end

Isso expõe fubar como um método público em Acronyms, mas mantém a coragem interna (fu e bar) privado e oculta o módulo auxiliar da visão externa.

Se alguém corrigiu um objeto ou módulo, então você precisa examinar 2 casos:Ele adicionou um novo método.Se ele for o único a adicionar este método (o que é muito provável), então não surgirão problemas.Se ele não for o único, você precisa ver se os dois métodos fazem o mesmo e informar o desenvolvedor da biblioteca sobre esse problema grave.

Se eles mudarem um método, você deve começar a pesquisar por que o método foi alterado.Eles mudaram isso devido a algum comportamento extremo ou realmente corrigiram um bug?especialmente neste último caso, o monkeypatch é uma coisa divina, porque corrige um bug em muitos lugares.

Além disso, você está usando uma linguagem muito dinâmica, partindo do pressuposto de que os programadores usam essa liberdade de maneira sensata.A única maneira de remover essa suposição é não usar uma linguagem dinâmica.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top