Curso MIT "Segurança de sistemas de computadores". Aula 11: Linguagem de Programação Ur / Web, Parte 3

Instituto de Tecnologia de Massachusetts. Curso de Aula nº 6.858. "Segurança de sistemas de computador". Nikolai Zeldovich, James Mickens. 2014 ano


Computer Systems Security é um curso sobre o desenvolvimento e implementação de sistemas de computador seguros. As palestras abrangem modelos de ameaças, ataques que comprometem a segurança e técnicas de segurança baseadas em trabalhos científicos recentes. Os tópicos incluem segurança do sistema operacional (SO), recursos, gerenciamento de fluxo de informações, segurança de idiomas, protocolos de rede, segurança de hardware e segurança de aplicativos da web.

Palestra 1: “Introdução: modelos de ameaças” Parte 1 / Parte 2 / Parte 3
Palestra 2: “Controle de ataques de hackers” Parte 1 / Parte 2 / Parte 3
Aula 3: “Estouros de Buffer: Explorações e Proteção” Parte 1 / Parte 2 / Parte 3
Palestra 4: “Separação de Privilégios” Parte 1 / Parte 2 / Parte 3
Palestra 5: “De onde vêm os sistemas de segurança?” Parte 1 / Parte 2
Palestra 6: “Oportunidades” Parte 1 / Parte 2 / Parte 3
Palestra 7: “Sandbox do Cliente Nativo” Parte 1 / Parte 2 / Parte 3
Aula 8: “Modelo de Segurança de Rede” Parte 1 / Parte 2 / Parte 3
Aula 9: “Segurança de aplicativos da Web” Parte 1 / Parte 2 / Parte 3
Palestra 10: “Execução Simbólica” Parte 1 / Parte 2 / Parte 3
Aula 11: “Linguagem de Programação Ur / Web” Parte 1 / Parte 2 / Parte 3

A última coisa que precisamos fazer e que será muito instrutiva é alterar esse código indicando o módulo da sala lá e, em seguida, tentar acessar a tabela da sala, como no exemplo anterior. Esta opção não é permitida porque isso não é permitido.



Seria como ser capaz de ler e escrever campos de classe privada em Java. De fato, recebemos uma mensagem bastante simples, basicamente dizendo que temos uma variável não relacionada aqui, uma expressão desconhecida para o parâmetro room.



Poderíamos mencionar este módulo complementar, que criamos apenas por diversão.



Mas então haverá tabelas diferentes. Podemos acessá-lo facilmente. Portanto, vou dividi-lo em duas partes, começaremos simplesmente chamando o método room e, em seguida, faremos algo ligeiramente diferente para ler seus elementos.



Exibir uma lista de resultados, e não vice-versa, isso é aproximadamente equivalente ao funcionamento do programa antes, exceto pelo uso de vários tipos de dados. Vamos ver o que vem disso. Agora voltamos ao nosso bate-papo na sala 1 e inserimos qualquer mensagem na linha. Você vê que todos eles são exibidos sem erros.



Ou seja, agora temos esse encapsulamento, para que você possa pensar na estrutura dessa sala como uma biblioteca, mas não precisa se preocupar com isso.

Existem vários lugares que podem danificar a invariância interna de um sistema. Talvez você queira que, após a adição da mensagem, ela nunca desapareça. Tudo isso está nas revistas. Essa estrutura fornece essas propriedades independentemente de outro código, como aquele em que o módulo da sala de bate-papo está gravado.

Aluno: para você alterar a definição da sala, o que aconteceria com a tabela do banco de dados nesse caso?

Professor: você precisa executar manualmente o comando alter table para manter os dados antigos. Mas quando o aplicativo é iniciado, ele consulta o diretório do banco de dados do sistema e verifica se o esquema ainda está conforme o esperado. Então você receberá um erro estático. Espero que isso lhe dê uma idéia do que você deve alterar no banco de dados.

Aluno: mas não excluirá automaticamente o banco de dados ou algo assim?

Professor: Espero que não. Eu não acho que o compilador deva fazer isso. Você pode imaginar personalizar o compilador para entender a evolução do banco de dados. Eu acho que você precisa escrever comandos alter table para iniciar, porque o compilador não faz isso agora.



Vamos agora falar sobre a falsificação de solicitações entre sites e sua prevenção. De fato, antes de fazermos isso, vejamos o código nesta página. Temos um formulário HTML tradicional que é gerado aqui. E, é claro, não há proteção contra a falsificação de solicitações entre sites, e acho que é bom. Porque, pelo que entendi, o problema de falsificar solicitações entre sites é o contexto implícito que o aplicativo envia com cada solicitação.

Suponha que exista algum tipo de invasor que não conheça seu contexto implícito. Digamos que sua senha esteja armazenada em um cookie, para um exemplo muito simples. E quando o invasor o engana ao clicar no link para o aplicativo que ele precisa, o navegador envia automaticamente um contexto implícito e obriga o aplicativo a fazer o que o invasor não poderia fazer diretamente.



Nesse caso, não há contexto implícito; portanto, não há risco de falsificar solicitações entre sites. Alguém quer desafiar esse recurso do sistema antes de continuar? Pode ser muito informativo para mim. Caso contrário, adicione um contexto implícito aqui. Nesse caso, o sistema adotará automaticamente as contramedidas corretas, com base na análise do programa, que entende que agora existe um contexto implícito.

Agora vou inserir cookies aqui. Como outro exemplo de encapsulamento de módulo, de fato, colocarei aqui todo um sistema de autenticação de usuário no qual temos contas de usuário e tipos abstratos de identificadores e senhas. Portanto, você não pode simplesmente criar o valor de qualquer um desses tipos de dados diretamente. Você terá que passar por algum método aprovado de construção de valores desses tipos.

Vou colocar a mesa na assinatura. E também imporemos uma restrição, dizendo que a chave é o formulário de identificação.



Mas o fato é que nessa tabela de usuários, o ID e a senha são tipos de dados abstratos. Portanto, o código não pode ver a senha e não pode gerar consistentemente todos os identificadores e experimentá-los nesta tabela. Porque ele usa um tipo abstrato, pelo qual é impossível estabelecer a aparência do ID e é impossível encontrar uma senha. Eles vêm dessa tabela e são tokens opacos.

Mas poderíamos permitir que eles fossem usados ​​como esgoto. Convém permitir uma direção de conversão entre cadeias e esses tipos. Agora farei algo aqui, principalmente os detalhes, e não tentarei explicá-los. Mas isso é como declarar que você tem permissão para converter seqüências de caracteres em ID. Para aqueles familiarizados com Haskell, essa é uma classe de tipo instantâneo, essa permissão para transformar seqüências de caracteres em IDs.



Não vamos aplicar outra permissão, porque não queremos poder transformar o ID novamente em outra coisa. Vamos fazer o mesmo pela senha. Queremos poder ler a senha do usuário, mas não vamos aceitá-la e transformá-la em uma string que nos dirá que o usuário entrou no bate-papo.

Assim, outras partes do código poderão aceitar a senha do usuário, convertê-la nesse tipo e transportá-la para o módulo do usuário para verificação. Mas o que eles não podem fazer é consultar a tabela do usuário e obter todas as senhas em um formulário a partir do qual eles podem extrair sua expressão de texto.

Então, podemos ter um método de login que aceite esses dois componentes, ID e senha, e apenas funcione como efeito colateral, o que é realmente declarado no código. Também precisaremos de uma maneira de descobrir qual usuário está registrado. Este é o código que executa a transação que cria o ID.



O primeiro passo é simplesmente copiar esta definição. E então vem uma surpresa. Acontece que os IDs e senhas de usuário são cadeias de caracteres, mas essa circunstância não será divulgada fora do módulo.



Agora vamos criar cookies. Cookies são outra coisa incorporada ao idioma. De fato, eles agem como variáveis ​​globais mutáveis ​​que possuem uma cópia para cada cliente que usa seu aplicativo.

Assim, vamos criar um cookie que para cada usuário simplesmente armazene uma cópia dos mesmos dois campos que temos aqui.



Esses cookies são privados para este módulo. Outras partes do código não poderão ler cookies, porque simplesmente não possuem esse campo privado. Portanto, ninguém poderá ver diretamente o ID e a senha salvos para este usuário. Mas eles serão salvos ao visualizar várias páginas, como é o caso de cookies comuns.

Agora vou inserir a função de login, que iniciará o processo para verificar o banco de dados e descobrir se esse é realmente o par correto de nome de usuário e senha. Esse processo apenas verifica se podemos encontrar uma linha no banco de dados que contém esse ID do usuário e senha.

Se o encontrarmos, então bom, então este é o significado correto. Vamos apenas salvar isso em cookies. Usamos um método que altera o valor de um cookie. E temos que colocar algumas coisas aqui, para simplificar vou dizer que esse cookie não expira. Não quero executar SSL aqui, por isso direi que neste caso não precisamos de segurança e defina o parâmetro Secure = false.

Mas se você realmente se importa com segurança, obviamente escreverá Secure = true. Se a verificação falhar e o módulo sinalizar um erro, o programa será interrompido, fornecendo uma descrição desse erro.



Por fim, podemos criar essa função que informa qual usuário específico está logado recebendo o valor atual do cookie. Este parâmetro também pode ser definido como none se o usuário ainda não tiver efetuado login. Nesse caso, receberemos outra mensagem de erro. Ou pode ser algum tipo de registro do tipo exato que usamos acima. Então, basta copiar aqui e executar a mesma verificação. Se isso funcionar, simplesmente retornamos a parte do registro de ID que acabamos de verificar no banco de dados.



Então deixe-me ver isso. Iniciamos o compilador e você vê o resultado na tela.



Central para todos esses detalhes de implementação. Mas fora deste módulo, pensamos sobre isso do ponto de vista da interface. Existem alguns tipos desconhecidos de IDs e senhas. Esta tabela de usuário expressa termos que permitem transformar cadeias de caracteres em identificadores e senhas, mas não vice-versa. Temos esses dois métodos para inserir o login primeiro e há uma verificação de qual usuário está conectado nesse estágio. Tem perguntas sobre isso?

Aluno: Você precisa expandir a tabela de usuários?

Professor: Eu faço isso porque quero usá-lo mais tarde como uma chave estrangeira, portanto, esse não é um motivo importante. Portanto, estamos quase no ponto em que posso mostrar a proteção contra CSRF em ação.

Para começar, é muito fácil fazer login no sistema. Bem, o que mais podemos fazer neste momento do programa? Vamos apenas adicionar aqui outra parte da página que diz que é aqui que você insere o login. Aqui você deve inserir o nome de usuário e a senha e clicar no botão de ação de envio. Esta ação fornecerá uma chamada para a função de login.



Vamos definir o login como uma função que faz essas coisas. Na verdade, é apenas um invólucro que chama a função de login deste módulo, na qual pegamos cada um dos componentes e convertemos de uma sequência para um tipo abstrato.



Ela verifica se há um erro de leitura. O erro significa que, se o login não funcionar, a operação será interrompida neste momento e a função retornará à parte principal do programa.
Agora podemos fazer login. Provavelmente, queremos criar uma conta que permita o login, por isso, deixe-me criar um usuário com nome de usuário ae senha a.





Agora eu posso logar como usuário a, aceite minha palavra. Como temos um conjunto de cookies para registrar essas informações, vamos para a sala de bate-papo e enviar uma mensagem, por exemplo, asfasf. Você vê que, depois de clicar no botão Adicionar, ele apareceu no bate-papo.



De fato, não adicionamos nenhum controle de acesso aqui, então nada de especial acontece aqui. Mas podemos verificar.



Existem cookies aqui, mas o sistema determinou que não usamos cookies. Quando enviamos este formulário, o cookie não é legível. Portanto, até o momento não há necessidade de adicionar proteção CSRF aqui. Portanto, agora precisamos adicionar uma maneira de usar cookies e ver como a proteção se manifestará.

Aluno: o que é conteúdo de cookie?

Professor: esse é o conteúdo que você espera receber do código. Em outras palavras, o cookie é declarado como tendo o tipo desse registro - identificador e senha.



Portanto, é exatamente isso que está contido em um determinado formato serializado. Agora vamos realmente usar cookies. Deveríamos ver isso, apesar de usarmos o cookie indiretamente, porque vamos usá-lo no módulo room, que não tem nada a ver com cookies. Mas chamaremos métodos de módulo personalizado que estão indiretamente relacionados ao uso de cookies. E então o sistema entenderá que isso significa que somos dependentes dele.

Então, vamos fazer de maneira muito simples e chamar o método whoami. Na verdade, eu vou ignorá-lo, ou vice-versa, deixá-lo fazer alguma coisa. Vamos decidir que o usuário que criamos é realmente especial e apenas esse usuário pode postar qualquer coisa. Se não for esse o caso, receberemos uma mensagem de erro.



Vou adicionar um ID ao módulo do usuário, e isso deve funcionar, pois o tipo de ID oferece suporte à verificação de igualdade.



Agora tudo deve estar em ordem e podemos fazer mais coisas com esse ID, o que pode causar alguns problemas de segurança.



Isso nos permite adicionar uma verificação de controle de acesso, então vamos ver como funciona e retornar à página principal.



Agora, essas quatro letras "a" apareceram no bate-papo.

No console da interface, vemos que agora o formulário recebeu automaticamente o nome de entrada oculto sig, que é a assinatura criptográfica dos valores de todos os cookies. Este sig assinou cookies usando uma chave que é secreta para o servidor. E quando o formulário está pronto, o aplicativo sabe - porque o compilador falou sobre isso - que o aplicativo deve verificar as assinaturas para o próximo conjunto de operações. Para isso, temos uma operação say.



Aluno: as assinaturas têm algum tipo de carimbo de data / hora?

Professor: não, as assinaturas não possuem registro de data e hora.

Aluno: nesse caso, se um invasor conseguir "espionar" esses dados, ele poderá fingir ser um usuário, porque esses cookies nunca expirarão.

Professor: sim, nunca expira. Isso pode ser alterado simplesmente alterando a implementação do idioma sem alterar os aplicativos e implantando-o rapidamente. Mas agora isso não está aqui. E eu entendo por que isso seria útil adicionar.

Aluno: você também pode corrigir isso simplesmente colocando um carimbo de data / hora na assinatura.

Professor: sim, você está certo, você pode alterar o aplicativo de forma a alterar intencionalmente os dados do cookie com frequência suficiente, ou seja, fazer a assinatura expirar.
Aluno: você pode reatribuir URLs?

Professor: sim, que transferência você gostaria de ver?

Aluno: qualquer, só quero ver como isso é feito.

Professor: Então, o compilador atribui ... como vemos, chamamos a função say, e essa chamada de função é serializada como uma forma específica de URL. Suponha que não gostemos deste formulário.



Decidimos reescrever a URL, por assim dizer, dentro do módulo da sala, dentro da demonstração. Melhor aguentar. Então, queremos reatribuir o URL Demo / Room / say para Demo / Room / Speak.



Iniciamos o compilador e vamos para a tela principal do aplicativo. Vamos ver o que acontece. Está tudo em ordem, também podemos inserir mensagens de texto e elas aparecerem na linha de bate-papo. Você pode usar caracteres imprevisíveis nessas regras para substituir um prefixo por outro, e o compilador garantirá que cada função tenha um esquema de URL separado, mas o URL é gerado automaticamente por padrão.

Aluno: você mencionou que o HTML não é específico do compilador, é apenas uma biblioteca. Existem outras bibliotecas para outros formatos?

Professor: existem outras bibliotecas que não verificam o tipo com a mesma integridade funcional, mas, por exemplo, há uma biblioteca para serializar e desserializar JSON, e um grande número de maneiras automatizadas de gerenciar a estrutura de tipos. Dessa forma, você pode fazer coisas que não estão integradas ao compilador.

Aluno: suponha que ainda queremos escrever em JavaScript, por exemplo, para animar algumas coisas na página ...

Professor: deixe-me baixar a versão Ajax disso, que responderá sua pergunta. Esta versão possui código do lado do cliente. Vamos seguir para uma versão do programa chamada demo3. Eu inseri os dados na página principal na linha de bate-papo, e eles também apareceram na parte inferior do bate-papo. Acredite ou não, desta vez o suplemento funcionou usando uma chamada Ajax. Isso ocorre devido ao valor do botão da tag do botão. Possui um atributo onclick, que, quando o usuário clica no botão, todo esse código abaixo da linha com esse atributo funciona no lado do cliente.

]

Mas esse é o código Ur / Web, não é o código JavaScript. O compilador traduz isso em JavaScript para você e garante que ele salve as propriedades que desejamos para abstrações em nossa lista, se o usuário não quiser mexer manualmente com ele no navegador.

Estudante: Eu acho que hoje existem muitas bibliotecas que fazem coisas úteis e, em muitos casos, coisas complexas, se você quiser recodificar tudo. Existe alguma maneira de interagir com JavaScript do Ur / Web?

Professor: sim, existe uma interface de função externa que permite atribuir nomes de funções Ur / Web a nomes e chamadas de funções JavaScript. Mas quando você usa a interface de uma função externa, não pode mais usar todas essas funções úteis de construção. Nesse caso, você precisa ter muito cuidado.

Você deve entender a implementação de algumas dessas abstrações para não interferir com elas. Enquanto eu tiver esse código, deixe-me mostrar outra coisa.

Ainda temos a mesma função de dizer como antes. Mas agora, em vez de chamá-lo por referência, apenas recebemos uma chamada de função, que é preenchida com argumentos que vêm do contexto do manipulador onclick.



Simplesmente envolvemos essa função na sintaxe rpc. Isso significa que essa é uma função de chamada do lado do cliente, mas a chamada em si é iniciada no servidor com acesso ao banco de dados e outros recursos do servidor e depois transfere o resultado para aqui.

, , JavaScript .
, . , , , .



, , , . , , .

, - , . GUI , , , , .

, , , . , DOM. , , .



, GUI, , , , .

, , .

: ?

: , , . , - .

: . , ?



:a melhor maneira é fazer com que as pessoas usem essas coisas e relatem bugs. Este é o melhor conselho que posso lhe dar. A idéia é que esses compiladores sejam escritos com muito menos frequência do que os novos aplicativos. Porque ele coleta todos os erros em um só lugar e tenta eliminá-los, mesmo que isso não ocorra da maneira mais eficaz.

Aluno: por que você escolheu esse nome para o seu idioma - Ur?

Professor: Ur é um conceito da linguística, o nome da língua que é o ancestral da linguagem moderna. E a idéia é que esse idioma permita inserir todos os tipos de outros idiomas dentro dele. Portanto, este é um tipo de progenitor de todas as línguas.


A versão completa do curso está disponível aqui .

Obrigado por ficar conosco. Você gosta dos nossos artigos? Deseja ver materiais mais interessantes? Ajude-nos fazendo um pedido ou recomendando a seus amigos, um desconto de 30% para os usuários da Habr em um análogo exclusivo de servidores básicos que inventamos para você: Toda a verdade sobre o VPS (KVM) E5-2650 v4 (6 núcleos) 10GB DDR4 240GB SSD 1Gbps da US $ 20 ou como dividir o servidor? (as opções estão disponíveis com RAID1 e RAID10, até 24 núcleos e até 40GB DDR4).

VPS (KVM) E5-2650 v4 (6 núcleos) 10GB DDR4 240GB SSD de 1Gbps até dezembro de graça quando pagar por um período de seis meses, você pode fazer o pedido aqui .

Dell R730xd 2 vezes mais barato? Somente nós temos 2 TVs Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100 a partir de US $ 249 na Holanda e nos EUA! Leia sobre Como criar um prédio de infraestrutura. classe usando servidores Dell R730xd E5-2650 v4 custando 9.000 euros por um centavo?

Source: https://habr.com/ru/post/pt426001/


All Articles