Por favor, faça seu idioma analisável / auditável para pessoas de segurança de computadores.
O pessoal de segurança precisa encontrar vulnerabilidades em um programa antes de ele ser lançado. Idealmente, somos chamados no início e podemos comentar a base de código à medida que ela se desenvolve, mas geralmente não.
Quando uma nova versão da linguagem ou das bibliotecas principais é lançada, as coisas anteriormente seguras podem não ser mais:
- bibliotecas podem se tornar mais poderosas: por exemplo, a biblioteca de URL agora suporta
javascript:
- pode haver novas maneiras de converter seqüências de caracteres ou bytes em código: por exemplo,
eval
ou bibliotecas de desserialização
- técnicas de reflexão de linguagem podem se tornar mais poderosas: por exemplo, expor variáveis locais
Qualquer uma dessas alterações pode aumentar a quantidade de autoridade abusiva que um programa possui, mas como a quantidade de autoridade que o programa usa (ao lidar com clientes não maliciosos) não mudou, o pessoal da segurança é pressionado a descobrir isso sem uma intensa re-auditar.
Portanto, pense em nós ao projetar e fazer o versionamento da linguagem. Abaixo estão algumas dicas:
Defina algumas primitivas em que um programa pode ser decomposto.
O HTML5 é particularmente ruim dessa maneira. Obviamente, eles pensaram muito em segurança e têm pessoas muito inteligentes, mas, em vez de especificar novos elementos do programa, como <video>
em termos de antigos, ou criar uma abstração comum na qual novos <video>
e antigos <img>
podem ser especificados em termos de, <video>
ainda é outro elemento do programa pontual com suas próprias conseqüências de segurança.
Torne seu idioma passível de análise estática (mesmo se não for digitado estaticamente).
O pessoal da segurança costuma usar a análise estática para encontrar padrões e tentar descartar partes de um programa para que possam se concentrar nos bits realmente complicados.
Deveria ser óbvio quais identificadores são variáveis locais e quais não são.
Por exemplo, não cometa o mesmo erro das versões antigas do JavaScript, o que impossibilitou dizer se x
é uma referência de variável local a seguir (de acordo com uma leitura literal de uma versão antiga da especificação):
if (Math.random() > 0.5) {
Object.prototype.x = 0;
}
function f() {
var x = 1;
(function () {
alert(x); // Might alert 0, might alert 1.
})();
}
Permitir segurança decomponível
Muitos sistemas seguros são projetados em torno de um kernel seguro que preserva as propriedades de segurança, para que os profissionais de segurança possam concentrar seus esforços na análise de uma pequena quantidade de código e liberando a maioria dos programadores de lidar com pessoas de segurança {irritantes, pedantes e paranóicas} .
Deveria ser possível escrever um kernel no seu idioma. Se uma das propriedades de segurança do seu idioma é que apenas um determinado subconjunto de URLs será buscado, os criadores do kernel podem fazer algo para canalizar todas as URLs que buscam pelo código? Ou as verificações de construção estática (como observar as importações) podem ter a mesma função.
Algumas linguagens como o Newspeak usam um modelo de recursos de objetos. Isso é incrível e é uma ótima maneira de obter segurança decomponível.
Mas se você não puder fazer isso, tornar o gráfico do módulo um artefato estaticamente analisável pode lhe trazer um grande benefício. Se eu puder provar que um módulo não pode alcançar o módulo de E / S de arquivo (exceto chamando o código em um módulo no TCB), então posso descartar classes inteiras de problemas desse módulo.
Limitar a autoridade das linguagens de script incorporadas
Muitos sistemas úteis são organizados como um núcleo estático que inicia muito código escrito em linguagens dinâmicas (até funcionais).
E a incorporação de linguagens de script pode tornar um sistema muito mais extensível.
Mas uma linguagem de script não deve ter a autoridade total da VM.
Se você optar por permitir linguagens de script incorporadas, facilite ao invocador limitar o que ele pode fazer. Um modelo de recursos de objetos (veja o comentário no Newspeak acima) é muito apropriado aqui; portanto, ao avaliar o código em uma linguagem de script, o chamador deve passar o código para executar e todas as variáveis globais para esse código.
Tratar eval
como uma linguagem incorporada a si mesma como uma linguagem de script
Se o seu idioma puder invocar seu próprio compilador para transformar uma cadeia de caracteres em código, permita que ela seja colocada na área de proteção da mesma maneira que faria com qualquer linguagem de script incorporada.
Use um modelo de simultaneidade simples
Nós, pessoal de segurança, não gostamos de nos preocupar com as condições da corrida ao tentar descobrir se uma propriedade de segurança é mantida.
Por favor, considere alternativas ao encadeamento antes de instalar os encadeamentos como uma opção padrão quase impossível de proteger.
Uma simples é a simultaneidade de loop de eventos como a encontrada em E, Verilog e JavaScript.
Não incentive citando confusão
Alguns idiomas são colados e acabam lidando com strings em vários idiomas diferentes.
Por exemplo, o JavaScript geralmente compõe cadeias de caracteres de HTML, CSS, XML, JSON e até JavaScript. É muito difícil para os programadores lembrarem-se de codificar corretamente as strings de texto sem formatação ao combiná-las para criar strings em outras linguagens; assim, os programas JS, sem surpresa, têm todo tipo de citação de problemas de confusão: o XSS é o pior.
Se você deseja incluir recursos de composição de cadeias, tente reduzir a carga de segurança do programador. DSLs, macros higiênicas e linguagens de modelagem incorporadas podem ser uma ótima maneira de fazer isso, movendo o ônus de escapar adequadamente para os desenvolvedores de bibliotecas ou idiomas e para longe do desenvolvedor final.