Eu gostaria de dar uma rápida olhada na história da programação de cura (programação defensiva). A programação segura é um dos princípios da programação * , também conhecida como programação defensiva . É um conceito antigo, mas não é um daqueles incompreendidos ou incompreendidos?

  • Descrito como Programação Defensiva .

Por que não é geralmente entendido como senso comum? A razão pode estar na história da programação defensiva.

referência:

Conteúdo [ oculto ]

  • 1 Incidente em que foi reconhecida a necessidade de programação segura
  • 2 Desenvolvimento de técnicas de ataque e defesa
  • 3 programação segura
  • 4 Princípios de programação segura
    • 4.1 Estrutura básica do código
    • 4.2 Princípios Básicos do Código Seguro
    • 4.3 Princípios Básicos do Código Seguro
    • 4.4 Estrutura básica de um aplicativo seguro
  • 5 Resumo
    • 5.1 Princípios de Codificação/Programação Seguros
    • 5.2 Validação de entrada exigida pela codificação segura
    • 5.3 Codificação Segura em 5 Minutos
    • 5.4 Referência
    • 5,5 Total
    • 5.6 Relacionado

Incidentes em que a necessidade de programação segura foi reconhecida

Os conceitos básicos de segurança informática são estudados desde a década de 60. Com base nesses resultados, a ARPANET , antecessora da Internet , começou a operar em 1969. Conceitos que ainda são relevantes hoje foram concebidos. No entanto, eu não ignorei a segurança, mas grosso modo, nas décadas de 60, 70 e 80, focamos em “criar programas” e “criar programas seguros” não era muito enfatizado. .

Os computadores de antigamente eram muito mais fracos do que hoje em termos de CPU, memória e armazenamento, e não havia rede de longa distância. O PC era autônomo e monotarefa, e é claro que não havia nenhuma proteção de memória, e não havia necessidade da “segurança” que agora é necessária para programas rodando neste ambiente. Não era necessário, mas não era viável em computadores sem modo kernel/tarefa única/sem proteção de memória. No ambiente UNIX, que era chamado de estação de trabalho, havia modo kernel e modo de usuário, proteção de processo multiprocesso e proteção de memória. No entanto, não era tão comum quanto hoje os computadores serem conectados a redes de longa distância. Grandes computadores chamados mainframes usavam redes dedicadas.

Em outras palavras, no passado, quase não havia necessidade de pensar em “ataques de fora”, e “tudo bem desde que o programa funcionasse” com “dados programados”. Devido a limitações de hardware, como CPUs fracas, memória/armazenamento pequeno e lento e redes finas, a criação de programas compactos e eficientes foi priorizada em relação à segurança. Devido a esta situação, alguns dos princípios de programação da época estão agora obsoletos. (O mesmo processo é único e inválido. Programas seguros implementam defesa em profundidade/defesa em profundidade.)

Ataques usando buffer overflows são conhecidos * desde pelo menos 1972 . Mesmo que a possibilidade de um ataque seja apontada, as contramedidas não progridem a menos que haja um dano real. De fato, de 1972 a 1988 houve pouca preocupação em defender programas contra ataques de estouro de buffer.

O incidente que mudou isso foi o Morris Worm de 1988 , que se diz ser o primeiro worm de Internet da história . Nessa época, a Internet já havia sido construída e computadores (estações de trabalho UNIX) em várias universidades e institutos de pesquisa estavam conectados à Internet. Naquela época, o UNIX tinha os recursos de segurança necessários para multiusuários, como isolamento de processo/proteção de memória/kernel e modo de usuário, mas nem sequer tinha a capacidade de se defender contra ataques simples de estouro de pilha. O worm Morris também usa rsh e sendmail, mas usa stack overflow do fingerd . Para obter mais informações , consulte o artigo que analisa o worm Morris . Um ataque que destrói essa memória e executa código arbitrário tem um impacto enorme e mudará a maneira como você pensa sobre segurança.

Os aplicativos/software naqueles dias tinham muitas vulnerabilidades de estouro. Naturalmente, não tive a ideia de me defender. Era uma época em que o sistema operacional era tão vulnerável que seria impensável do ponto de vista do sistema operacional atual. Pensava-se que problemas semelhantes ocorreriam um após o outro. Foi logo após o incidente do Morris Worm (2/11/1988) (30/11/1988) que o CERT foi criado para coordenar a correção e divulgação de vulnerabilidades de segurança .

Desenvolvimento de tecnologia de ataque e defesa

Desde o worm Morris, tornou-se amplamente reconhecido que as medidas de segurança para os próprios programas são importantes, em vez de simplesmente isolar redes e processos. Entende-se que a defesa do sistema operacional por si só não é suficiente, e a defesa da rede (firewalls de rede são usados ​​desde o final da década de 1980. Antes disso, a filtragem por roteadores * ) e aplicativos são essenciais, e é necessária uma programação defensiva. .

O lado atacante desenvolve ataques de injeção de memória que podem sequestrar computadores remotamente um após o outro. No início, era um simples estouro de pilha, mas ataques usando estouro de número inteiro e estouro de área de heap foram planejados. Os ataques de injeção vão além da memória. Os computadores se espalharão para tudo que armazena e usa informações significativas.

Embora nenhuma fonte tenha sido encontrada para identificar sua origem, é provável que variantes de ataques de injeção, como injeção de caractere nulo, injeção de cabeçalho de email e injeção de XML, tenham sido criadas nessa época.

A primeira DEF CON será realizada em 1993 . DEF CON é uma competição de técnica de ataque de computador + conferência de segurança que ainda está sendo realizada hoje. Os materiais da primeira edição estão disponíveis no site . Pouco depois de 1997, será realizada a conferência Black Hat. Assim como o DEF CON, o Black Hat também atrai a atenção todas as vezes. Os materiais da primeira edição também estão disponíveis no site . Conferências de segurança como DEF CON/Black Hat contribuem muito não apenas para o desenvolvimento da tecnologia de ataque, mas também para o desenvolvimento de defensores.

Não é como se os desenvolvedores também não tivessem feito nada. Desde o incidente do worm Morris, a direção mudou de “criar um programa que funcione” para “criar um programa que funcione com segurança”. Eu tenho Code Complete (Microsoft Press em inglês) e há uma seção sobre 5.6 Programação Defensiva. Acontece que foi publicado em 1993, mesmo ano do DEF CON.

Deve ter sido antes de 1993 que a programação defensiva foi reconhecida como essencial para a programação segura. Não consegui encontrar a fonte, mas acho que o conceito foi concebido por volta do ano seguinte ao Morris Worm (2 de novembro de 1988 para o incidente do Morris Worm). Parece.

Como você pode ver na cronologia simplificada acima, nenhum novo método de ataque foi desenvolvido por cerca de 10 anos após o Morris Worm. Isso provavelmente ocorre porque existem muitos programas que podem ser atacados apenas atacando a vulnerabilidade de estouro de pilha e não houve necessidade de criar um novo método de ataque.

Durante esse período, pode ter havido um equívoco generalizado de que a programação defensiva era uma medida de segurança necessária apenas para linguagens que podem manipular diretamente a memória, como C. Certamente, nos anos 90, a programação defensiva era frequentemente discutida como uma defesa contra ataques de corrupção de memória. Isso pode ser porque a programação defensiva foi identificada erroneamente como uma técnica de programação C e não se tornou muito popular .

No entanto, lembro que o conceito básico de programação defensiva, “todas as entradas externas não são confiáveis”, não se limitava a ataques de corrupção de memória. Não seria estranho ter tal livro/documento, mas o conceito básico de entrada externa não confiável e saída segura e confiável permanece o mesmo. Eu não acho que nenhum cientista da computação sábio limitaria “todas as entradas externas” por causa da percepção equivocada de que um estouro de buffer apenas travaria o programa.

A cronologia mostra que novos ataques de injeção foram concebidos relativamente recentemente. E, assim como o Stack Overflow, 15 anos após o aviso de vulnerabilidade, as vulnerabilidades de injeção de JavaScript continuam sendo as principais vulnerabilidades em aplicativos da web. Existem muitas razões pelas quais a injeção de JavaScript é estruturalmente difícil de lidar, e o desenvolvimento da Web geralmente é um desenvolvimento em pequena escala, dificultando a transmissão de conhecimento para novos desenvolvedores. Uma das razões é que o “controle confiável de entrada e saída” mais importante e eficaz não foi introduzido como medida de segurança. O número de vulnerabilidades e ataques deixa claro que a defesa contra ataques de injeção é de suma importância para um programa seguro.

A programação defensiva é agora considerada um dos princípios da programação e também é chamada de programação segura. Esses são os princípios básicos que são essenciais para construir um software seguro, então você precisa se certificar de que os segue.

Programação Segura

“Programação defensiva” é um nome para imagens reativas. O comportamento/pensamento ativo/proativo é essencial para garantir um nível mais alto de segurança. É impossível alcançar um nível mais alto de segurança resolvendo problemas de forma patchwork toda vez que algo dá errado. Os programas também são passivos, resolvendo problemas específicos sempre que surgem. É impossível eliminar completamente os problemas em seu programa.

“Programação segura” em vez de “programação defensiva” enfatiza medidas proativas em vez de reativas. Eu suspeito que é por isso que o termo alternativo “programação segura” foi inventado.

Recentemente, acho que o nome “codificação segura” e a ênfase na escrita de código são frequentemente usados. Acho que isso é considerado mais fácil de entender. Programação defensiva, programação segura e codificação segura são basicamente o mesmo conceito.

Elementos de programação segura vêm em muitas formas diferentes. Elementos e conceitos individuais não são difíceis. A Programação Defensiva da Wikipedia cita os seguintes elementos:

  • Reutilização inteligente do código-fonte
  • Manipulação segura de entrada e saída
  • Canonização (converter para a forma canônica antes de processar)
  • Baixa tolerância contra bugs “potenciais”
  • Outras técnicas
    • uso não verificado de estruturas e funções de tamanho constante para dados de tamanho dinâmico (contramedidas de estouro de buffer)
    • Criptografe/autentique todos os dados importantes transmitidos pelas redes (usando criptografia e autenticação)
    • Todos os dados são importantes até prova em contrário. (Não confie em nada além de dados validados e confiáveis)
    • Todos os dados estão corrompidos até prova em contrário.
    • Todo código é inseguro até prova em contrário.
    • Se os dados devem ser verificados quanto à exatidão, verifique se eles estão corretos, não se estão incorretos. (Use a lista de permissões)
    • Projeto por contrato
    • Asserções (usando a função assert da linguagem de programação)
    • Prefira exceções a códigos de retorno

As 10 principais práticas de codificação segura do CERT listam os seguintes elementos:

Referência: tradução japonesa das 10 principais práticas de codificação segura

  1. Validar entrada
  2. Preste atenção aos avisos do compilador (não ignore os avisos do compilador, use também as ferramentas de análise)
  3. Arquitetar e projetar políticas de segurança
  4. Mantenha simples
  5. Negar padrão
  6. Aderir ao princípio do privilégio mínimo
  7. Higienize os dados enviados para outros sistemas
  8. Pratique a defesa em profundidade
  9. Use técnicas eficazes de garantia de qualidade
  10. Adote um padrão de codificação seguro

O CWE/SANS TOP 25 Erros Mais Perigosos lista as Mitigações de Monstros como um elemento comum de programação segura . * As medidas de mitigação são definidas como “medidas de segurança” na ISO 27000 .

  1. Estabeleça e mantenha o controle sobre todas as suas entradas.
  2. Estabeleça e mantenha o controle sobre todas as suas saídas.
  3. Bloqueie seu ambiente.
  4. Suponha que componentes externos possam ser subvertidos e seu código possa ser lido por qualquer pessoa.
  5. Use recursos de segurança aceitos pelo setor em vez de inventar os seus próprios.

O Guia de Referência Rápida de Práticas de Codificação Segura (PDF) do OWASP lista:

Referência: tradução japonesa do Guia de Referência Rápida de Práticas de Codificação Segura OWASP

  • Validação de entrada
  • Codificação de Saída
  • Autenticação e gerenciamento de senhas
  • Gerenciamento de sessão
  • Controle de acesso
  • Práticas criptográficas
  • Tratamento e registro de erros
  • Proteção de dados
  • Segurança de comunicação
  • Configuração do sistema
  • Segurança do banco de dados
  • Gerenciamento de arquivos
  • Gerenciamento de memória
  • Práticas gerais de codificação

Uma característica distintiva das diretrizes do OWASP é a “Codificação de Saída”. A codificação é uma forma de pensar que estende o conceito de fuga, e pode-se dizer que está escapando + α. A ideia é codificar com mais segurança, em vez de escapar apenas do que deveria ser escapado por especificação. Também apoio fortemente esta ideia.

Guias de programação segura do CERT, SANS e OWASP também são designados como fontes de melhores práticas para os padrões PCI DSS . PCI DSS é um padrão obrigatório para empresas de desenvolvimento que lidam com cartões de crédito, cartões de débito, etc. Ou seja, para essas empresas, os guias de programação segura do CERT, SANS e OWASP são diretrizes para medidas de segurança que devem ser implementadas em suas aplicações.

Embora as palavras sejam diferentes, existem coisas como “Validar sua entrada”, “Usar lista de permissões”, “Fornecer saída segura”, “Usar práticas recomendadas” e “Confiança/segurança é algo que você verifica”. Localização é a ideia básica .

“Adotar as melhores práticas” também traz um problema. Existem algumas coisas que são consideradas práticas recomendadas, mas não são de fato ( seguras desde que você use consultas preparadas , etc.) ou estão em processo de implementação. Além disso, algumas medidas de segurança estão comprometidas (piorando gradualmente, criptografia, hash, etc.). Em alguns casos, novas técnicas de ataque podem comprometer as técnicas tradicionais (como compressão criptográfica). Em alguns casos, foram concebidas melhores medidas de defesa do que antes*. É importante ter autenticidade.

*Na verdade, revisões recentes do site OWASP atualizaram o método recomendado de escape de JavaScript. Ainda não o apresentei neste blog, por isso, se possível, gostaria de apresentá-lo em breve.

Princípios de programação segura

A programação segura baseia-se nos princípios fundamentais de como os computadores funcionam. Desde o momento em que o primeiro programa foi escrito até os dias atuais, todos os programas têm a mesma estrutura básica.

Um estado de segurança satisfatório não pode ser alcançado com medidas/estruturas de segurança que não se encaixam na estrutura básica.

Estrutura básica do código de todos os programas

  • Entrada → Processo → Saída

tem a estrutura de

image

Princípios Básicos do Código Seguro

O coração de um programa é o “processamento” (lógica) .) dados de entrada” é um requisito absoluto .

Ao emitir dados “processados”, deve-se garantir que seja inofensivo para o destino de saída . Por exemplo, ao enviar uma instrução SQL para um banco de dados, é responsabilidade do programa garantir que a instrução SQL seja completamente inofensiva, o que é um pré-requisito absoluto para que os dados de saída funcionem corretamente.

  • Funciona corretamente = Funciona sem falhas = Funciona sem problemas de segurança

  • Embora muitas vezes seja mal interpretado, as medidas de segurança não são basicamente deixadas para a “API de chamada”. Isso só pode ser feito se puder ser garantido como confiável. Isso também é frequentemente mal interpretado, mas é o ponto de que “o escopo da confiança é limitado”. A API não é responsável por processar adequadamente o que você passar.

As entradas e saídas são protegidas com defesas de perímetro nos limites de confiança para garantir o comportamento correto do programa.

image

Princípios básicos de código seguro

Os princípios básicos são os das 10 principais práticas de codificação seguras. O princípio da defesa do perímetro é especialmente importante.

  • validação de entrada
  • Sanitização de Saída

Vamos implementá-los sem falhas. Não são poucos os casos em que as pessoas interpretam mal a frase “sem vazamentos”. Por exemplo, usar apenas consultas preparadas em consultas SQL é cheio de buracos .

Os aplicativos da Web ainda estão em um estado em que o processamento de entrada é muito frágil. Se o processamento de entrada for frágil, fica difícil garantir a segurança.

image

Estrutura básica de um aplicação seguro

Uma aplicação segura protege a defesa do perímetro com defesa em profundidade.

image

Normalmente, todos os módulos/funções/métodos não possuem defesa completa do perímetro. A responsabilidade de garantir a defesa completa é das defesas de perímetro no nível do aplicativo. Por esse motivo, a defesa do perímetro no nível do aplicativo é a mais importante*.

*É importante proteger os limites de entrada/saída com a parte externa do aplicativo.

https://blog.ohgaki.net/there-are-3-types-of-validations

Resumo

No início da escrita, eu pretendia “olhar brevemente para a história” com um pouco mais de detalhes, mas como sempre, tornei-me um blog que não escrevo. Eu sinto Muito.

Os desenvolvedores e operadores do sistema estão alcançando os invasores? Esta pergunta é importante. Acho que não estamos nos acertando. É por isso que a programação segura (programação defensiva) é tão importante. A Carnegie Mellon University, que opera o CERT, também está desenvolvendo o CMMI (Capability Maturity Model Integration). Ele foi desenvolvido com base na ideia de que é mais realista mudar a organização passo a passo para uma organização que pode realizar um desenvolvimento seguro a partir da realidade de que é difícil alcançar o desenvolvimento seguro em uma etapa.

Saltar para o desenvolvimento seguro é difícil, mas o conceito de programação segura não é difícil. Práticas de programação seguras podem ser iniciadas mais ou menos rapidamente. Mas quantas organizações de desenvolvimento de software estão fazendo isso? Não parece muito. A maioria das estruturas atuais de desenvolvimento de aplicativos da Web possui recursos de validação, mesmo que sejam inadequados. Aproveite ao máximo. Aproveite as bibliotecas disponíveis e confiáveis. Se você não tiver um recurso, construa-o com cuidado.

É importante praticar programação segura em cada função/método dentro do programa, mas o mais importante é proteger toda a aplicação. Para proteger todo o aplicativo, é importante implementar programação segura (validação de entrada, saída segura – escape (codificação), uso seguro de API, validação) no limite do aplicativo, ou seja, na entrada e saída do aplicativo.

O conceito de programação segura é simples, mas sinto que muitas vezes não é praticado ou mesmo compreendido (?). A programação segura é essencial para o desenvolvimento de software seguro.

Você pode pensar que se você verificar cada função uma por uma, ela ficará lenta e haverá um problema no uso prático. Esse problema também está documentado no Code Complete. Linguagens que suportam programação de contrato podem resolver facilmente esse problema. A prática baseada em princípios de programação de contrato deixa apenas verificações de entrada/saída no nível do aplicativo. No entanto, isso é perigoso, então não se esqueça de introduzir “defesa em profundidade” (defesa em profundidade) em um nível apropriado.

Finalmente, a medida mais importante na segurança de software é a defesa do perímetro no limite de confiança . Primeiro, a defesa do perímetro é executada, seguida pela defesa em profundidade/defesa em profundidade. É muito importante, portanto, esteja ciente de onde e que tipo de limite de confiança existe ao programar.

Princípios de codificação/programação seguros

Validação de entrada exigida pela codificação segura

Codificação segura em 5 minutos

Referência


Autor: Yasuo Ogaki

Artigo Original