Segurança em Aplicações Rails

Segurança em Aplicações Rails

RubyConf Brasil 2016: #rubyconf #rails #security

49e8a75b7e9c4c8b30c00bdc9eda0533?s=128

Diego Rossini Vieira

September 24, 2016
Tweet

Transcript

  1. das falhas comuns até as não tão óbvias Segurança em

    aplicações Rails
  2. DIEGO ROSSINI VIEIRA @diegorv

  3. DIEGO ROSSINI VIEIRA @diegorv

  4. consulting and software engineering

  5. None
  6. None
  7. None
  8. Vamos falar de Segurança

  9. Toda aplicação tem ou terá uma vulnerabilidade de segurança

  10. "Não a minha!" - Pessoa inocente

  11. "Não a minha!" - Pessoa inocente

  12. "Segurança por obscuridade não é segurança, mas ilusão”

  13. "Segurança por obscuridade não é segurança, mas ilusão”

  14. Maiores vazamentos de dados do mundo Fonte: http://www.informationisbeautiful.net/visualizations/worlds-biggest-data-breaches-hacks

  15. None
  16. None
  17. None
  18. Projeto Aberto de Segurança de Aplicações Web

  19. OWASP TOP 10 - 2013 A1 Injeção de código A2

    Quebra de autenticação e Gerenciamento de Sessão A3 Cross-Site Scripting (XSS) A4 Referência Insegura e Direta a Objetos A5 Configuração Incorreta de Segurança A6 Exposição de Dados Sensíveis A7 Falta de Função para Controle do Nível de Acesso A8 Cross-Site Request Forgery (CSRF) A9 Utilização de Componentes Vulneráveis Conhecidos A10 Redirecionamentos e Encaminhamentos Inválidos
  20. "O óbvio só é óbvio para os olhos preparados"

  21. Segurança é algo complicado!

  22. Mas e o Rails?

  23. SQL Generation (SQL injection) Rails é bastante seguro por padrão

  24. None
  25. Payload ‘ or 1=1;

  26. SELECT * FROM users WHERE email = '?' ‘ or

    1=1;
  27. SELECT * FROM users WHERE email = '?' ‘ or

    1=1;
  28. SELECT * FROM users WHERE email = '‘ or 1=1;'

  29. SELECT * FROM users WHERE email = ‘\’ or 1=1;’

  30. Rails é bastante seguro por padrão Cross-site Request forgery (CSRF)

  31. 1 2 3 4 Atacante cria um site falso com

    o mesmo layout do original O usuário recebe esse site falso e submete o formulário O site falso tem um formulário que aponta para o site original aonde o usuário provavelmente está logado O site original recebe esse formulário e faz uma ação diferente da intenção do usuário
  32. <form action="http://site-original.com.br/users" method=“post"> <div> <label>Email</label> <input type="email" value="vitima@vitima.com.br" name="user[email]"> </div>

    <div> <label>Alterar senha</label> <input type="password" name="user[password_fake]"> <input type="hidden" name="user[password]" value=“senha-do-atacante“ /> </div> <div> <input type="submit" value="Atualizar conta"> </div> </form>
  33. class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising

    an exception. protect_from_forgery with: :exception end
  34. <form action="http://site-original.com.br/users" method=“post"> <input type="hidden" name="authenticity_token" value="5Y4eMio0xwYvt4ANZ=="> <div> <label>Email</label> <input

    type="email" value="vitima@vitima.com.br" name="user[email]"> </div> <div> <label>Alterar senha</label> <input type="password" name="user[password_fake]"> <input type="hidden" name="user[password]" value=“senha-do-atacante“ /> </div> <div> <input type="submit" value="Atualizar conta"> </div> </form>
  35. None
  36. HTML Sanitization (XSS) Rails é bastante seguro por padrão

  37. <h1>Bem vindo ao meu site</h1> <% if params[:message] %> <%=

    params[:message] %> <% end %>
  38. None
  39. <h1>Bem vindo ao meu site</h1> <% if params[:message] %> <%=

    params[:message].html_safe %> <% end %>
  40. None
  41. None
  42. None
  43. Você sabe aonde o Rails não te protege?

  44. http://guides.rubyonrails.org/security.html

  45. 1.Sessions 2.CSRF 3.Redirection and Files 4.Intranet and Admin Security 5.User

    Management 6.Injection 7.Unsafe Query Generation 8.Default Headers 9.Environmental Security 10.Additional Resources http://guides.rubyonrails.org/security.html
  46. LEIA O RAILS GUIDES

  47. Atenção com SQL Injection

  48. http://rails-sqli.org

  49. User.where("email = '#{params[:email]}'")

  50. params[:email] = "') or (admin='1" User.where("email = '#{params[:email]}'")

  51. User.where("email = '#{params[:email]}'") SELECT * FROM users WHERE (email =

    '') or (admin='1') params[:email] = "') or (admin='1"
  52. User.where('email = ?', params[:email])

  53. User.where('email = ?', params[:email]) params[:email] = "') or (admin='1"

  54. User.where('email = ?', params[:email]) params[:email] = "') or (admin='1" SELECT

    * FROM users WHERE (email = '\') or (admin=\'1')
  55. average calculate count maximum minimum sum delete_all destroy_all exists? find_by

    where from group having joins lock order pluck reorder select update_all API vulnerável do ActiveRecord
  56. Atenção com Sessions

  57. Session Fixation: A sessão NUNCA expira! • Dado que você

    tenha um cookie de um usuário, você pode acessar a aplicação para sempre como esse usuário Atenção com Sessions
  58. Session Fixation: A sessão NUNCA expira! Atenção com Sessions Rails.application.config.session_store

    :cookie_store, key: '_app_session', expire_after: 2.hours
  59. Atenção com XSS

  60. O HREF do link_to NÃO é escapado Atenção com XSS

  61. Sanitize todos os campos de URLs que você salva no

    banco user.homepage_url = "javascript:alert('hello')" link_to "Homepage", user.homepage_url <a href="javascript:alert('hello')">Homepage</a> Atenção com XSS
  62. Atenção com CSRF

  63. Não funciona com rotas GET match 'products/:id/purchase' => 'catalog#purchase' Atenção

    com CSRF
  64. Adeus proteção se alguém tirar o protect_from_forgery class ApplicationController <

    ActionController::Base # TODO: Não quero usar isso aqui, depois eu dou um jeito # protect_from_forgery with: :exception end Atenção com CSRF
  65. Não confie em nenhum dado enviado pelo usuário

  66. Não confie em nenhum dado enviado pelo usuário

  67. • params • cookies • headers • url path Não

    confie em nenhum dado enviado pelo usuário • upload de arquivos • requisições ajax • elementos do DOM • qualquer coisa!!!!!!!!!
  68. Isso é a base que você deveria conhecer!

  69. Me conta mais…

  70. 1. Proteção contra XSS

  71. None
  72. None
  73. Proteção contra XSS https://github.com/twitter/secureheaders Considere a gem secureheaders

  74. 2. No Rate Limiting

  75. None
  76. Ataques de Brute Force No Rate Limiting

  77. Web Scraping No Rate Limiting

  78. Requests excessivos No Rate Limiting

  79. Mais isso é uma bobagem… No Rate Limiting

  80. 2016: Como eu poderia ter hackeado todas as contas do

    Facebook Fonte: http://www.anandpraka.sh/2016/03/how-i-could-have-hacked-your-facebook.html
  81. 2016: Como eu poderia ter hackeado todas as contas do

    Facebook Fonte: http://www.anandpraka.sh/2016/03/how-i-could-have-hacked-your-facebook.html
  82. None
  83. POST /recover/as/code/ HTTP/1.1 Host: beta.facebook.com em[0]=email@email.com&n=XXXXXX

  84. Oi, Brute Force! POST /recover/as/code/ HTTP/1.1 Host: beta.facebook.com em[0]=email@email.com&n=XXXXXX

  85. Considere a gem rack-attack No Rate Limiting https://github.com/kickstarter/rack-attack

  86. No Rate Limiting • Track de usuários específicos Considere a

    gem rack-attack
  87. • Configurar safelist e/ou blocklist No Rate Limiting Considere a

    gem rack-attack
  88. • Throttles: Bloquear requests excessivos No Rate Limiting Considere a

    gem rack-attack
  89. • Integrar com Fail2Ban No Rate Limiting Considere a gem

    rack-attack
  90. 3. Referência Insegura e Direta a Objetos

  91. def update payment = Payment.find(params[:id]) end Referência Insegura e Direta

    a Objetos Não escopada
  92. def update payment = Payment.find(params[:id]) end Referência Insegura e Direta

    a Objetos Não escopada
  93. def update payment = current_user.payments.find(params[:id]) end Referência Insegura e Direta

    a Objetos Escopada
  94. def update payment = current_user.payments.find(params[:id]) end Referência Insegura e Direta

    a Objetos Escopada
  95. Mais isso é uma bobagem… Referência Insegura e Direta a

    Objetos
  96. Fonte: http://www.fidelis.work/como-eu-usei-o-cartao-de-credito-do-ceo-do-trampos-co-para-pagar-minha-assinatura-premium/ 2016: "Como eu usei o cartão de crédito

    do CEO do Trampos.co para pagar minha assinatura premium"
  97. Fonte: http://www.fidelis.work/como-eu-usei-o-cartao-de-credito-do-ceo-do-trampos-co-para-pagar-minha-assinatura-premium/ 2016: "Como eu usei o cartão de crédito

    do CEO do Trampos.co para pagar minha assinatura premium"
  98. card = Card.find_by(id: params[:card_id]) pagar_me_card = PagarMe::Card.find_by_id(card.pagar_me_id) transaction = PagarMe::Transaction.new(card:

    pagar_me_card) Não escopada
  99. card = current_user.cards.find_by(id: params[:card_id]) transaction = PagarMe::Transaction.new(card: card) Escopada

  100. Mais isso é uma bobagem… Referência Insegura e Direta a

    Objetos
  101. Fonte: https://hackerone.com/reports/27404 2014: "Deletar cartões de crédito de qualquer conta

    no ads.twitter.com"
  102. Fonte: https://hackerone.com/reports/27404 2014: "Deletar cartões de crédito de qualquer conta

    no ads.twitter.com"
  103. Mais isso é uma bobagem… Referência Insegura e Direta a

    Objetos
  104. Fonte: http://randywestergren.com/united-airlines-bug-bounty-an-experience-in-reporting-a-serious-vulnerability/ 2015: "United Airlines, alterar/visualizar qualquer passagem de avião"

  105. Fonte: http://randywestergren.com/united-airlines-bug-bounty-an-experience-in-reporting-a-serious-vulnerability/ 2015: "United Airlines, alterar/visualizar qualquer passagem de avião"

  106. Conexão original Man in the Middle

  107. Conexão original X Nova conexão Man in the Middle

  108. "Access to all of the flight’s departures, arrivals, the reservation

    payment receipt, personal information about passengers (phone numbers, emergency contacts), and the ability to change/cancel the flight."
  109. Referência Insegura e Direta a Objetos Como o usuário já

    estava logado no aplicativo, a API confiava nas requests.
  110. 4. Exposição de Dados Sensíveis

  111. Exposição de Dados Sensíveis APIs podem expor informações

  112. None
  113. None
  114. None
  115. None
  116. None
  117. Verifique se a sua API não está expondo mais informações

    que o client que vai consumir ela precisa Exposição de Dados Sensíveis APIs podem expor informações
  118. Exposição de Dados Sensíveis APIs podem expor informações Verifique se

    você se preocupa com a segurança da sua API da mesma forma que você se preocupa com a segurança do seu site
  119. Jan, 2015 Fonte: http://www.pcworld.com/article/2866872/apple-blocks-tool-that-bruteforces-icloud-passwords.html

  120. def TryPass(apple_id, password): url = 'https://fmipmobile.icloud.com/fmipservice/device/'+apple_id headers = { 'User-Agent':

    'FindMyiPhone/376 CFNetwork/672.0.8 Darwin/14.0.0' } Fonte: https://github.com/hackappcom/ibrute/blob/master/id_brute.py
  121. def TryPass(apple_id, password): url = 'https://fmipmobile.icloud.com/fmipservice/device/'+apple_id headers = { 'User-Agent':

    'FindMyiPhone/376 CFNetwork/672.0.8 Darwin/14.0.0' } Fonte: https://github.com/hackappcom/ibrute/blob/master/id_brute.py
  122. Exposição de Dados Sensíveis Headers podem expor informações

  123. 401 - Unauthorized = Existe e não tenho acesso! 404

    - Not found = Não existe?! Exposição de Dados Sensíveis Headers podem expor informações
  124. Exposição de Dados Sensíveis A linguagem pode expor informações

  125. “Senha incorreta” = Acertei o usuário “Usuário ou senha incorretos”

    = Senha ou usuário? Exposição de Dados Sensíveis A linguagem pode expor informações
  126. “E-mail não cadastrado no sistema” = Não tem esse e-mail!

    “Caso exista, enviamos o e-mail” = Tem esse e-mail? Exposição de Dados Sensíveis A linguagem pode expor informações
  127. Exposição de Dados Sensíveis URLs podem expor informações - Credential

    Enumeration www.site.com/user/1 = id do usuário www.site.com/client/3984739874 = cpf do cliente
  128. IDs sequenciais São potencialmente perigosos • Expõem a quantidade de

    registros que existem • Facilidade para ataques usando os próprios endpoints da aplicação
  129. Fonte: https://nandovieira.com.br/usando-uuid-no-postgresql-com-activerecord

  130. Fonte: http://blog.bigbinary.com/2016/04/04/rails-5-provides-application-config-to-use-UUID-as-primary-key.html

  131. Exposição de Dados Sensíveis Ataque de temporização

  132. Usuário existente Usuário inexistente

  133. Usuário existente Usuário inexistente

  134. # It will change confirmation, password recovery and other workflows

    # to behave the same regardless if the e-mail provided was right or wrong. # Does not affect registerable. config.paranoid = true Devise
  135. module Devise module Strategies class DatabaseAuthenticatable < Authenticatable def authenticate!

    resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash) hashed = false if validate(resource){ hashed = true; resource.valid_password?(password) } remember_me(resource) resource.after_database_authentication success!(resource) end mapping.to.new.password = password if !hashed && Devise.paranoid fail(:not_found_in_database) unless resource end end end end
  136. Usuário existente? Usuário inexistente?

  137. Usuário existente? Usuário inexistente?

  138. Qualquer coisa que pode ser medida, pode ser comparada

  139. 5. Segurança em dados criptografados

  140. Segurança em dados criptografados Se for criptografar algo, use um

    algoritmo correto
  141. PASSWORD = 'abcdefghij' BCRYPT_DIGEST = BCrypt::Password.create(PASSWORD, cost: 13) MD5_DIGEST =

    Digest::MD5.hexdigest(PASSWORD) SHA1_DIGEST = Digest::SHA1.hexdigest(PASSWORD) SHA256_DIGEST = Digest::SHA256.hexdigest(PASSWORD) SHA384_DIGEST = Digest::SHA384.hexdigest(PASSWORD) SHA512_DIGEST = Digest::SHA512.hexdigest(PASSWORD) Benchmark.ips do |x| x.report('md5') { Digest::MD5.hexdigest(PASSWORD) == MD5_DIGEST } x.report('sha1') { Digest::SHA1.hexdigest(PASSWORD) == SHA1_DIGEST } x.report('sha256') { Digest::SHA256.hexdigest(PASSWORD) == SHA256_DIGEST } x.report('sha384') { Digest::SHA384.hexdigest(PASSWORD) == SHA384_DIGEST } x.report('sha512') { Digest::SHA512.hexdigest(PASSWORD) == SHA512_DIGEST } x.report('bcrypt') { BCrypt::Password.create(PASSWORD) == BCRYPT_DIGEST } x.compare! end Fonte: https://speakerdeck.com/fnando/criando-aplicacoes-web-mais-seguras
  142. Warming up -------------------------------------- md5 37.583k i/100ms sha1 37.561k i/100ms sha256

    32.718k i/100ms sha384 30.712k i/100ms sha512 28.692k i/100ms bcrypt 1.000 i/100ms Calculating ------------------------------------- md5 514.530k (± 2.6%) i/s - 2.593M in 5.043394s sha1 521.438k (± 3.0%) i/s - 2.629M in 5.046857s sha256 383.893k (±13.1%) i/s - 1.898M in 5.052521s sha384 305.295k (±13.0%) i/s - 1.505M in 5.024430s sha512 320.019k (± 9.9%) i/s - 1.607M in 5.077244s bcrypt 5.845 (±17.1%) i/s - 29.000 in 5.015230s Comparison ------------------------------------- sha1: 521438.2 i/s md5: 514530.1 i/s - same-ish: difference falls within error sha256: 383893.1 i/s - 1.36x slower sha512: 320019.4 i/s - 1.63x slower sha384: 305294.6 i/s - 1.71x slower bcrypt: 5.8 i/s - 89211.74x slower
  143. Segurança em dados criptografados Mais isso é uma bobagem…

  144. Fonte: http://cynosureprime.blogspot.com.br/2015/09/how-we-cracked-millions-of-ashley.html 2015: Como quebramos milhões de senhas do Ashley

    Madison de forma eficiente Fonte: http://arstechnica.com/security/2015/09/once-seen-as-bulletproof-11-million-ashley-madison-passwords-already-cracked/
  145. Fonte: http://cynosureprime.blogspot.com.br/2015/09/how-we-cracked-millions-of-ashley.html 2015: Como quebramos milhões de senhas do Ashley

    Madison de forma eficiente Fonte: http://arstechnica.com/security/2015/09/once-seen-as-bulletproof-11-million-ashley-madison-passwords-already-cracked/
  146. <?php $salt = md5($username . '::' . $pass); ?>

  147. <?php $salt = md5($username . '::' . $pass); ?>

  148. Segurança em dados criptografados Use Salt de forma correta "A

    função primária do Salt é defender contra ataques de dicionário"
  149. Isso gera um salt fixo salt = BCrypt::Engine.generate_salt pass_hash =

    BCrypt::Engine.hash_secret(password,salt) Fonte: http://dustwell.com/how-to-handle-passwords-bcrypt.html
  150. # File 'lib/bcrypt/password.rb', line 43 def create(secret, options = {})

    cost = options[:cost] || BCrypt::Engine.cost raise ArgumentError if cost > 31 Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost))) end Isso gera um salt randômico pass = BCrypt::Password.create(PASSWORD)
  151. “Isso tem a velocidade de 350 bilhões de tentativas de

    senha por segundo" Fonte: http://arstechnica.com/security/2012/12/25-gpu-cluster-cracks-every-standard-windows-password-in-6-hours
  152. “Isso tem a velocidade de 350 bilhões de tentativas de

    senha por segundo" Fonte: http://arstechnica.com/security/2012/12/25-gpu-cluster-cracks-every-standard-windows-password-in-6-hours 350 bilhões
  153. 6. Atualizações de software

  154. Atualizações de software Atualizar é uma dor? Pois não deveria

    ser.
  155. Atualizações de software Atualizar é uma dor? Pois não deveria

    ser.
  156. Atualizações de software Atualizar é uma dor? Causas? • Suite

    de testes: ruim? lenta? • Medo do comportamento das dependências?
  157. Atualizações de software GEMS • Chances para diversos problemas de

    segurança • Pense bem antes de adicionar mais uma dependência
  158. Atualizações de software https://github.com/rubysec/bundler-audit GEMS - Considere a gem bundler-audit

    • Verifica versões com vulnerabilidades no Gemfile.lock • Verifica gem sources inseguros
  159. Atualizações de software RAILS

  160. 0 4.5 9 13.5 18 2006 2007 2008 2009 2010

    2011 2012 2013 2014 2015 2016 8 2 12 18 10 12 1 4 2 2 2 Vulnerabilidades Fonte: https://www.cvedetails.com/product/22568/Rubyonrails-Ruby-On-Rails.html?vendor_id=12043 * CVE: Common Vulnerabilities and Exposures * CVEs do Rails
  161. Atualizações de software RAILS - Você deveria conseguir atualizar o

    mais rápido possível quando for um release de segurança
  162. • RabbitMQ, como você trata as mensagens? • Logs diferentes

    do Rails, você filtra dados? • Deveria auditar logs? • StatsD+Grafana para estatísticas de segurança • Brakeman no seu Build • Segurança do teu servidor • Autenticação apenas por SSH (keys) • Libere apenas as portas necessárias • … Outras coisas
  163. OWASP TOP 10 - 2013 A1 Injeção de código A2

    Quebra de autenticação e Gerenciamento de Sessão A3 Cross-Site Scripting (XSS) A4 Referência Insegura e Direta a Objetos A5 Configuração Incorreta de Segurança A6 Exposição de Dados Sensíveis A7 Falta de Função para Controle do Nível de Acesso A8 Cross-Site Request Forgery (CSRF) A9 Utilização de Componentes Vulneráveis Conhecidos A10 Redirecionamentos e Encaminhamentos Inválidos
  164. • Brakeman • rack-attack • bundler-audit • security-headers Ferramentas

  165. • Rails Security Guides • Brakeman • https://www.owasp.org • http://bit.ly/ruby-sec-ann

    • https://github.com/OWASP/railsgoat Aprender
  166. • Rails Security Guides • Brakeman • https://www.owasp.org • http://bit.ly/ruby-sec-ann

    • https://github.com/OWASP/railsgoat Aprender
  167. None
  168. Responsible Disclosure Tome cuidado como você expõem uma falha

  169. Responsible Disclosure Rails Fonte: http://rubyonrails.org/security/ • Envie um email para

    a lista de segurança: security@rubyonrails.org • Contate diretamente o atual coordenador de segurança: Rafael França • Contate diretamente o contato de backup: Jeremy Daer
  170. Responsible Disclosure Outras GEMs/Sites/Serviços • Contate diretamente o autor da

    GEM • Contate diretamente o site/serviço
  171. UFA!

  172. UFA!

  173. Segurança deve ser um processo

  174. Segurança deve ser um processo Não existe isso de "óbvio"

  175. Segurança deve ser um processo Segurança não é uma feature

  176. Segurança deve ser um processo Mas deveria ser um requisito

    da sua feature
  177. Segurança deve ser um processo Envolva todas as pessoas do

    seu time
  178. Segurança deve ser um processo Promova revisões de código com

    seu time
  179. Segurança deve ser um processo Não trate segurança apenas como

    uma reação
  180. Segurança deve ser um processo Torne o pensamento sobre segurança

    uma constância
  181. OBRIGADO !! eu@diegorv.com @diegorv D https://speakerdeck.com/diegorv/seguranca-em-aplicacoes-rails