terça-feira, 1 de maio de 2012

Organizando a lógica de negócio



Martin Fowler é considerado um dos papas na área de arquitetura de aplicações - ele produziu muitos artigos e publicou 16 livros sobre o assunto (ou similares). Escrevendo de uma forma bem prática e didática, Fowler é uma das minhas principais fontes de orientação sobre o tema, e conseguiu sintetizar em 4 padrões de lógica de domínio - onde colocamos as regras de negócio, que podem nos ajudar muito na criação de novos projetos. Veja que a decisão de adotar um ou outro padrão pode nos ajudar a reduzir o trabalho de manutenção futura - Este pode ser o principal benefício, que deve ser avaliado pelo responsável do projeto. Ao final deste artigo, vou explicar um pouco melhor quando é melhor adotar um ou outro padrão - veja que é importante conhecer bem estes padrões, para depois poder escolher.


Mas precisamos antes contextualizar as 3 camadas, bem como suas responsabilidades em um sistema típico, para depois prosseguir na explanação dos padrões de organização da lógica de negócio:

  1. Apresentação - Camada que contém toda a lógica responsável pela manipulação das interações entre o sistema e o mundo exterior (usuário x sistema). Em resumo, esta camada é responsável por coletar os dados informados pelos usuários, e exibir os resultados dos processamentos realizados nas camadas mais profundas.
  2. Domínio - A camada de lógica de domínio também é denominada de lógica de negócios. Esta é a camada que funciona como o motor e cérebro do sistema, e faz o que deve ser feito. A lógica de domínio realiza os cálculos sobre os dados informados ou dados armazenados. Ele passa os dados para a camada de persistência, após ter validado a entrada da camada de apresentação.
  3. Fonte de dados - O propósito desta camada é principalmente comunicar-se com outros sistemas, como bancos de dados, sistemas de envio de mensagens e gerenciadores de transações. Em aplicações web, na maioria dos casos, estes sistemas serão sistemas serão gerenciadores de bancos de dados.

Agora vamos prosseguir. Os padrões para organizar a lógica de negócios são:




  • Transaction Script (Script transacional)  
  • Domain Model (Modelo de Domínio) 
  • Table Module (Módulo de Tabelas)  
  • Service Layer (Camada de Serviços)  


  • O Gama foi concebido adotando um misto entre os três primeiros, mas temos exemplos do uso de todos ao longo dos projetos que já desenvolvemos na IASoft.


    Transaction Script (Script transacional)
    http://martinfowler.com/eaaCatalog/transactionScript.html
    Organiza a lógica de negócio em procedimentos onde cada procedimento trata uma simples requisição da camada de apresentação (interface do usuário);

    A maioria das aplicações pode ser pensada como uma série de transações. Cada interação entre a interface e o servidor possui uma certa quantidade de lógica de negócio. Em alguns casos pode ser uma simples exibição de informações do banco de dados. Em outras, pode envolver muitos passos de validação e cálculos.

    Um Transaction Script organiza toda esta lógica, primariamente em um simples procedimento, fazendo chamadas diretamente para o banco de dados, ou através de uma camada de abstração. Cada transação terá seu próprio Transaction Script, embora seja comum que tarefas possam ser quebradas em subprocedimentos.

    No nosso caso, usamos este padrão como ações das Actions.


    Domain Model (Modelo de Domínio)
    http://martinfowler.com/eaaCatalog/domainModel.html
    Um Modelo de Objetos, de um certo domínio, que incorpora tanto dados quanto comportamentos.

    A lógica de negócios pode ser muito complexa. Nem sempre é fácil organizar as regras para atender a diferentes casos e comportamentos. O Domain Model cria uma rede de objetos interconectados, onde cada um representa algum indivíduo significativo, seja grande como uma empresa, ou pequeno como uma simples linha de um formulário.

    No nosso caso, são os BOs.



    Table Module (Módulo de Tabelas)
    http://martinfowler.com/eaaCatalog/tableModule.html

    A single instance that handles the business logic for all rows in a database table or view.



    One of the key messages of object orientation is bundling the data with the behavior that uses it. The traditional object-oriented approach is based on objects with identity, along the lines of Domain Model (116). Thus, if we have an Employee class, any instance of it corresponds to a particular employee. This scheme works well because once we have a reference to an employee, we can execute operations, follow relationships, and gather data on him.


    One of the problems with Domain Model (116) is the interface with relational databases. In many ways this approach treats the relational database like a crazy aunt who's shut up in an attic and whom nobody wants to talk about. As a result you often need considerable programmatic gymnastics to pull data in and out of the database, transforming between two different representations of the data.


    A Table Module organizes domain logic with one class per table in the data-base, and a single instance of a class contains the various procedures that will act on the data. The primary distinction with Domain Model (116) is that, if you have many orders, a Domain Model (116) will have one order object per order while a Table Module will have one object to handle all orders.


    Table Module is many ways the middle man between a Transaction Script and a Domain Model. A Table Module tends to organize domain logic with one class per table in the database. While a Transaction Script will have one class Hotel to do reservations a Table Module may have more fine grained classes like Hotel, Booking, Room. Even though these classes may be singular they do not actually represent individual entities and manages whole collections of entities. For example a Booking class would be responsible for mosts actions performed on the bookings database table. Like a Transaction Script a Table Module is a very data centric model approach and usually has a strong connection with the data access layer. Table Module has a few benefits over a Transaction Script. There’s less duplication, domain logic is more organized and structured around domain entities. It works well with simple data access layers. However, Table Module doesn’t give you full power of objects in organizing complex domain logic. It lacks instance to instance relationships, has weak support for polymorphism.


    Esta abordagem está muito associada com o modelo de dados, e por isso este deve ser bem definido.




    Service Layer (Camada de Serviços)
    http://martinfowler.com/eaaCatalog/serviceLayer.html
    Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.



    Enterprise applications typically require different kinds of interfaces to the data they store and the logic they implement: data loaders, user interfaces, integration gateways, and others. Despite their different purposes, these interfaces often need common interactions with the application to access and manipulate its data and invoke its business logic. The interactions may be complex, involv-ing transactions across multiple resources and the coordination of several responses to an action. Encoding the logic of the interactions separately in each interface causes a lot of duplication.


    A Service Layer defines an application's boundary [Cockburn PloP] and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coor-dinating responses in the implementation of its operations.


    Escolhendo o padrão


    Acredito que o aspecto mais importante para a escolha de um padrão de organização da lógica de negócio, é o da manutenção. Tanto a evolutiva quanto a corretiva:

    • Evolutiva - este é o principal aspecto, pois melhorias representam a inclusão de novos componentes, tais como classes e tabelas, bem como novas regras de negócios. 
    • Corretiva - a correção de bugs ou mesmo ajustes podem afetar outras partes do sistema, mas não devem, de forma alguma, alterar uma regra de negócio inadvertidamente. Por isso é importante saber onde elas estão.

    No gráfico abaixo, Martin Fowler apresenta o resultado de uma pesquisa, que demonstra a evolução do esforço de melhoria de um sistema, variando a complexidade da lógica de domínio, nos três principais padrões de organização da lógica de negócios.



    É possível perceber que pequenos projetos, com lógica de domínio mais simples, é preferível adotar o padrão Table Module - um gerador de CRUDs pode ser o mais adequado. Entretanto, caso o sistema cresça, a complexidade faz com que aumente o esforço de desenvolvimento (onde ficará uma regra de negócio, que afeta duas tabelas diferentes?).
    Pelo gráfico, pode ser um pouco mais trabalhoso iniciar o desenvolvimento adotando o padrão Transaction Script - ou seja, identificar as transações que responderão as demandas do mundo externo. No entanto, o aumento na complexidade do sistema vai representar um esforço ainda maior por parte da equipe.
    Por fim, Fowler mostra que usar a lógica centrada em um Domain Model é mais preditiva e linear: demanda um pouco mais de esforço no início, mas após um certo nível de evolução, fica mais fácil de manter do que os demais.


    Referências:




    segunda-feira, 30 de abril de 2012

    Segurança contra SQL Injection


    Ao desenvolver um sistema web, é quase certo que serão construídas queries SQL (a menos que use um framework que faça isso por você}. Tipicamente, o que ocorre é:
    1. Você cria um formulário que permite ao usuário submeter alguns dados;
    2. Seu script recupera os dados informados pelo usuário, e faz uma atribuição da mesma (global) à uma variável local, como no exemplo abaixo:
    $nome = $_POST['nome'];
    3. Agora o seu script usa o dado digitado pelo usuário, como parâmetro da query SQL.
    $sql = "SELECT * FROM usuarios WHERE nome = '{$nome}'";
    4. O seu script submete a consulta ao servidor de banco de dados.
    5. O servidor de BD retorna o resultado da consulta, que por sua vez é exibida ao usuário final.

    Este é um processo muito comum, e o que geralmente muda são os parâmetros e a consulta - no entanto o processo é geralmente o mesmo (ou muito similar).

    O problema está no momento em que a variável informada pelo usuário for intencionalmente forjada, como a seguir:

    admin' or 1=1

    o resultado da consulta é muito diferente do que normalmente se espera. De fato, agora são duas instruções em vez de uma: O que pode ocorrer neste caso, é que a consulta executada traga todos os registros da tabela usuarios. Dependendo da forma como estes dados são apresentados, é muito possível que o atacante possa obter acesso a dados além do que lhe seria permitido. O mesmo processo pode ser usado para burlar mecanismos de autenticação, obtendo a credencial do administrador por exemplo, sem ter a senha.
    Veja um exemplo de uma forma de ataque, que tenta injetar

    admin'; GRANT ALL ON *.* TO 'BadGuy@%' IDENTIFIED BY 'gotcha

    Embora a lista possa não recuperar nenhum registro, a consulta poderá criar uma autorização de acesso para o atacante. Este problema foi alvo de discussões especialmente no banco de dados MySQL - usado na grande maioria dos sites. Mas, o mesmo pode ocorrer com PostrgreSQL, SQLServer e até Oracle.

    Formas de prevenir o ataque de SQL Injection

    1. Delimite bem as consultas, colocando as variáveis do tipo string entre aspas;
    2. Verifique os tipos de dados enviados pelo usuário (string, numérico, data, etc), usando as funções intval(), gettype(), is_int(), etc.
    3. Valide o tamanho das variáveis entradas pelo usuário
    4. Verifique a presença de caracteres suspeitos no conteúdo enviado pelo usuário (como ponto-e-vírgula, aspas simples e duplas, por exemplo).
    5. Processe as variáveis, usando funções como addslashes(), por exemplo - isso quando aspas são admitidas, mas não podem ser "confundidas" pelo servidor de banco de dados.
    6. Crie uma camada de abstração para melhorar a segurança (uma classe intermediária pode ajudar a esconder detalhes da estrutura do banco de dados, por exemplo).
    7. Use os métodos de preparação das consultas, disponíveis nas funções de acesso ao banco de dados: No exemplo anterior:
    $sql = "SELECT * FROM usuarios WHERE nome = ? ";
    $stmt = mysqli_prepare( $connect,$sql);
    if ( $stmt ) {
    mysqli_stmt_bind_param( $stmt, "s", $usuario );
    }

    8. Teste sua aplicação contra um ataque.

    quarta-feira, 10 de junho de 2009

    Artigo interessante

    Hoje encontrei um artigo interessante: a apresentação 'Enterprise PHP development', feita por Ivo Jansch em fevereiro de 2008, na PHPLondon Conference, fala essencialmente de como desenvolver projetos sérios, de médio para grande porte, em PHP. Baixe aqui o artigo. Quem quiser ouvir a palestra, basta clicar aqui.

    O autor dá uma visão geral de como profissionalizar o desenvolvimento de um projeto, usando algumas figuras de linguagem bem humoradas. Vale a pena ler.

    segunda-feira, 6 de abril de 2009

    Os 5 Ms de Ahonen

    Tony Ahonen escreveu um livro entitulado "m-Profits – Making Money from 3G Services", onde discute amplamente o tema. Neste livro ele menciona os 5 Ms dos serviços 3G: "cinco elementos dos serviços 3G que agregam valor ao usuário, e lucro para a operadora".

    Os 5 Ms de Ahonen

    1. Movement (Movimento) - Escapando de um lugar fixo
    2. Moment (Momento) - Expandindo o conceito de tempo
    3. Me (Eu) - Extentendo a mim mesmo e a minha comunidade
    4. Money (Dinheiro) - Gastando recursos financeiros
    5. Machines (Máquinas / dispositivos) - "Turbinando" dispositivos


    1. Movement.
    O movimento é a habilidade do serviço a continuar operando de modo significativo enquanto que o usuário se desloca, seja por locais próximos, seja para longas distâncias.
    Até aqui nenhuma novidade; o que Ahonen enfatiza como ponto-chave, é que se o serviço possuir elementos que variam de acordo com a localização do usuário, então este comportamento deve ser realizado; Ele exemplifica a previsão de tempo: se o usuário estiver transitando de uma cidade para outra, o sistema deve verificar a previsão desta nova cidade.

    2. Moment
    O Momento é o conceito de possibilitar a gerenciar o tempo de modo a adaptar-se a situação em que se encontra; Um bom exemplo é o serviço de mensagens publicitárias baseadas na localização do usuário: um restaurante pode ter seus anúncions distribuídos próximos do almoço, e não as 23hs da noite, para os usuários que estiverem próximos.
    Outro ponto de vista do conceito de 'Moment' é a possibilidade de serem executadas várias tarefas simultaneamente: em um fluxo bem definido, tarefas relacionadas a um determinado fim podem ser distribuídas ou realizadas em paralelo, e sincronizadas pelo próprio sistema. Uma variante típica é a de iniciar uma tarefa que ficará "pendente" até o "momento certo": um exemplo é disparar a solicitação de um serviço (presencial), que será atendido daqui a 2 horas; quando chegar no local, o serviço será executado.


    3. Me
    "Me" é o conceito de personalização, que tem sido bem compreendido em alguns serviços Web, que adaptam-se de acordo com as configurações e perfil do usuário. Perceba que um ponto importante é o de que alguns parâmetros de configuração consistem de variáveis como o tempo (moment) e a localização (movement).
    Ahonem indica que o "Me" é o atributo mais vital dos 5 apresentados: é o ingrediente crítico para um serviço móvel bem-sucedido.
    Isso quer dizer que precisamos de uma plataforma flexível, o que implica em tecnologias que podem suportar um alto grau de customização, incluindo o conceito de que serviços podem algumas vezes serem construídos em tempo de execução, surgindo para atender demandas pontuais do usuário.
    A criação de serviços sob demanda é um novo elemento para a provisão de serviços no contexto móvel.

    4. Money
    Este é simplesmente o suporte para transações financeiras, onde quer que surja a necessidade.
    Evidentemente, um framework é necessário para permitir esse trabalho, dada a complexidade e a segurança envolvidas em transações de pagamentos.


    5. Machines
    O último 'M' é o conceito que permite que máquinas comuniquem-se através de redes WAN. Isso é algumas vezes chamado de M2M (machine to machine), e algumas vezes incrementado com a idéia de telemetria ou medições remotas sem a necessidade de pessoal de campo.
    Um bom exemplo são as máquinas de venda eletrônica, como máquinas de refrigerante, que "ligam" para a central e reportam os produtos que estão acabando.

    Tecendo minhas considerações

    Eu creio que dos 5 Ms, os 3 primeiros são os principais, para aplicações centradas em conteúdo móvel; para tanto, o estabelecimento de uma infraestrutura lógica é fundamental, e as 3 variáveis principais são, em ordem de importância: Identificação do usuário, Localização física e Tempo.

    quinta-feira, 5 de março de 2009

    Filtragem de caracteres indesejáveis

    Hoje o Juliano entrou em contato, pedindo uma ajuda para filtrar caracteres indesejáveis que vinham nos arquivos de dados...

    Depois de muito quebrar a cabeça, conseguimos o seguinte:


    1. Mudar o locale para português-Brasil

    setlocale(LC_ALL,"pt_BR.ISO8859-1");
    ou
    setlocale(LC_ALL,"pt_BR.UTF-8");

    2. Filtrar

    $v = preg_replace('/[^[:blank:]|[:space:]|[:alnum:]|[:punct:]]/', ' ', $v);


    segunda-feira, 2 de março de 2009

    #1 - Validação de Entrada de dados (primeira parte)

    Origem dos dados

    Originalmente, os programadores PHP acessavam dados enviados pelos usuários através dos mecanismos de "register globals".

    Usando "register globals", qualquer parâmetro passado para o script é disponibilizado como uma variável com o mesmo nome do parâmetro.

    Embora o mecanismo de "register globals" seja uma abordagem para capturar parâmetros pelos scripts, é uma vulnerabilidade e possível fonte de exploração por parte de hackers.

    Um dos problemas é o conflito entre os parâmetros de entrada: Dados fornecidos ao script podem vir de várias fontes, incluindo requisições GET, POST, cookies, variáveis de ambiente do servidor e variáveis de ambiente do sistema - nenhuma delas é exclusiva.

    Então, se as fontes são muitas, o PHP é forçado a mesclá-las, algumas vezes substituindo o valor de uma por outra de mesmo nome. Aqui reside o perigo: se temos uma variável esperada via cookie, um atacante pode enviá-la via método GET, e o script nem perceber a diferença, se usar a variável global.

    Portanto, é importante usar mecanismos que forcem a verificação da origem dos dados vindos do usuário.

    No arquivo de configuração PHP.INI existem duas diretivas de controle que são usadas como parâmetros para que o interpretador faça o merge: gps_order e variables_order. Ambos parâmetros refletem a prioridade relativa das fontes de entrada de dados.

    Não vamos entrar muito neste assunto, visto que já presumimos que usamos as variáveis superglobais ($_GET, $_POST, etc) para acessar tais dados. Entretanto, cabe uma orientação: mesmo usando as superglobais, existe um risco especialmente em casos em que criamos variáveis para verificar se um dado script foi carregado ou não (ou se tal arquivo pode ser incluído ou não) - nestes casos, como a variável pode estar exposta à configuração do servidor, cabe uma advertência: é melhor usar constantes (define) ao invés de usar uma variável simples. Isso porque a variável simples pode ser substituída por um parâmetro injetado por um atacante, se não estiver inicializada e dependendo da configuração do servidor.

    Outra observação importante, é o uso da superglobal $_REQUEST - ela mistura as variáveis GET, POST e COOKIES em um mesmo array. É o mesmo problema da register globals, embora em menor grau. Portanto, prefira o uso de $_GET ou $_POST.

    Conteúdo

    É importante sempre verificar a natureza do parâmetro de entrada e validá-lo para evitar problemas depois.

    Dados numéricos

    Se o dado esperado é numérico, simplesmente usamos o recurso de casting para obter o valor. Veja os exemplos a seguir:

    $id_produto = (int) $_GET['id_produto'];
    $valor_salario = (float) $_POST['valor_salario'];

    Para melhorar um pouco mais, podemos centralizar o casting onde de direito: nos getter e setters das classes:

    class Funcionario {

    private $valorSalario;


    public function getValorSalario() {
    return $this->valorSalario;
    }

    public setValorSalario($valor) {
    $this->valorSalario = (float) $valor;
    if (!$this->valorSalario) {
    $e = new Exception('Valor do salario deve ser float',999);
    throw $e;
    }
    }
    }


    Veja que no exemplo acima se ocorre um erro de tipo, uma excessão é imediatamente emitida e o programador já mata o problema na raiz. A abordagem acima pode ser melhorada incluindo na mensagem o valor que se está passando para o atributo em questão.

    Um ponto que deve ser observado com cuidado é a precisão do tipo numérico que se espera. Por exemplo: para validar um inteiro, em sistemas de 32 bits, é 2,147,483,647. Se uma string "1000000000000000000" for convertida para integer, ela vai estourar o container e haverá perda de dados. No caso, o resultado final será truncado no máximo possível, que é 2147483647.
    Então, fazendo o casting de números grandes na notação científica evitará a perda de dados:

    echo (int)"100000000000000000"; // 2147483647
    echo (float)"100000000000000000"; // float(1.0E+17)


    Enquanto que o casting funciona bem para inteiros e números de ponto-flutuante, valores em hexadecimal, octal e descritos em notação científica não são tratados automaticamente - é necessário implementar mecanismos adicionais de validação. O mais lento mas mais eficaz é a instrução "is_numeric" - Ela suporta todos os tipos de valores numéricos, e retorna True se o valor é válido.


    Problemas de internacionalização

    Algumas vezes números de ponto-flutuante são representados de várias formas ao redor do mundo, mas tanto o casting quanto o "is_numeric" consideram números que não usam o "ponto" (.) como separador decimal como inválido.

    O problema é que para a validação em si, não encontrei recursos nativos no PHP que consideram a entrada de dados em localizações (locales) diferentes. Os mecanismos de locales funcionam muito bem para exibir o resultado de valores no formato esperado na língua selecionada. Por isso, recomendo que se use rotinas que façam a conversão do conteúdo logo na entrada dos dados. Para o caso de dados númericos de ponto flutuante, eu uso:

    $r = setlocale(LC_ALL, 'ptb');
    $locale_info = localeconv();

    $numero = str_replace($locale_info['thousands_sep'],"",$numero_input);
    $numero = str_replace($locale_info['decimal_point'],".",$numero);

    Com a lógica acima, o script "sabe" quais caracteres espera que sejam entrados pelo usuário como separador decimal e de milhar. Automaticamente o valor é convertido para o formato que o interpretador "entende", e daí para adiante o valor é processado e depois inserido/atualizado no banco de dados; Depois, a exibição do dado fica por conta do interpretador, que vai considerar o locale selecionado. No caso do exemplo acima, defini a localização como sendo Português Brasileiro.


    Validação de String

    A validação de string não é tão simples quanto a de um atributo numérico, uma vez que o casting não é suficiente para garantir que o valor entrado é o esperado - existem algumas variantes que precisam ser consideradas. O primeiro ponto é o formato do valor entrado, que pode ser um CPF, número de telefone, URL, CEP, etc.

    Para verificar se uma string possui apenas caracteres alfabéticos, não sendo admitido qualquer número ou pontuação, pode-se usar a instrução 'ctype_alpha()'. A extensão CTYPE é habilitada por padrão no PHP. Existem outras instruções dessa extensão que podem ser úteis em questões bem particulares, mas nenhuma delas consiste regras de formação mais complexas. Veja ainda que a Ctype considera o locale ativo. Portanto, caracteres que são considerados inválidos no alfabeto inglês (como 'ç'), serão considerados válidos pela Ctype quando o locale PTB estiver setado.

    Quando o ctype é inútil para resolver um determinado problema de validação, recomenda-se usar expressões regulares. Com expressões regulares é possível realizar uma série de verificações bem complexas, tanto de conteúdo quanto do posicionamento deste no corpo do texto, e também múltiplas ocorrências de padrões de conteúdo.
    Para fazer tais verificações com o PHP, pode-se usar as instruções 'ereg' e seus semelhantes, bem como as instruções presentes na extensão PCRE, como a preg_match. Veja maiores detalhes do uso de cada uma destas opções no manual do PHP.


    Validação de tamanho de conteúdo

    Assim como dados numéricos, entradas de strings precisam atender certas especificações. As expressões regulares podem validar a sintaxe dos dados entrados, mas tabém é importante validar o tamanho da entrada.

    Uma falha que pode ser explorada por um atacante, consiste na geração de um valor que excede o tamanho do campo no banco de dados, e com isso um erro de banco será emitido - se este erro não for tratado, informações valiosas para o atacante poderão ser dadas.

    A solução deste problema possui duas partes: criar os formulários com mecanismos de verificação do conteúdo antes do envio dos dados ao servidor, e a verificação dos mesmos na entrada do script. Nos formulários os campos de textos podem ter tamanho máximo, com o atributo maxlength. Para campos de texto-livre (textarea) é necessário verificar o tamanho do conteúdo ao se enviar os dados, com funções javascript.


    Validação de Listas de Seleção

    Listas de valores onde o usuário pode selecionar um item (ou mesmo mais) é outro foco de atenção que o desenvolvedor deve ter. Veja que um atacante pode emular uma requisição injetando novos valores, que podem causar desde erros de processamento, passando por inconsistências, chegando a danificar parcialmente ou consideravelmente o sistema. Portanto, valores discretos como strings que podem ser usadas como chaves em listas de seleção, e até mesmo valores numéricos, devem ser verificados no lado do servidor antes de se prosseguir com o processamento da requisição.
    Para realizar essa validação, recomenda-se o uso de uma lista de valores em um array, que será usado na verificação da consistência do valor informado.

    sexta-feira, 27 de fevereiro de 2009

    Um pouco mais sobre segurança de arquiteturas web

    Autenticação

    Dicas importantes:
    • Use senhas fortes
    • Não armazene credenciais sem estarem codificadas em arquivos de codificação
    • Não transmita arquivos sem estarem criptografados pela rede
    • Não permita contas super-privilegiadas
    • Não permita sessões com tempo de vida prolongado
    • Permita a personalização e o armazenamento de informações de autenticação



    Autenticação de Realm

    Realm significa 'domínio' ou 'reino'. Tratando-se de ambiente de aplicações web, 'realm' significa uma área protegida.

    Autenticação de Realm é usada para proteger recursos dentro de um domínio que está disponível apenas para usuários autorizados.

    O método de autenticação para um 'realm' consiste em registrar um módulo de autenticação para o domínio e definir os atributos de configuração. Isso é feito a nível de servidor web.


    Passo-a-passo

    Quando um recurso em particular dentro do domínio é protegido usando a autenticação básica, e quando um usuário tenta acessá-lo, o servidor web envia um cabeçalho de requisição de autenticação (código 401) para o requisitante. Isso notifica o navegador que o recurso não pode ser acessado sem autenticação; em resposta, as credenciais do usuário devem ser supridas para que o recurso requisitado possa ser recuperado. Um formulário de login e senha é aberto pelo browser solicitando ao usuário que entre com seu username e senha. Você pode definir o método de autenticação como Basic ou Digest.

    Nunca use o método básico, porque nesta forma o usuário e a senha são enviados com cleartext, enquanto que no modo Digest a senha é codificada pelo browser usando o algoritmo MD5. Assim, se algum sniffer capturar os dados trocados entre o cliente e o servidor, só terá o hash, e não a senha.

    A autenticação baseada em Realm é diferente da autenticação de 'Realm'; Na autenticação baseada em Realm, o usuário pode se autenticar para um domínio ou subdomínio (subrealm). Você define diferentes domínios para recursos diferentes, e a autenticação do realm pode ser especificada em uma interface de login como parte da URL pela definição do parâmetro do realm ou parâmetro do domínio.


    Gerenciamento de Arquivos de Configuração

    Um sistema é a coleção de muitas partes. Estas partes geralmente incluem programas executáveis, arquivos de parâmetros para customizar o software para um determinado ambiente, e dados.
    Se um adversário obtém o arquivo de configuração, todo o sistema pode vir a estar vulnerável.
    Por isso é especialmente crítico que estes arquivos de parâmetros e de configuração sejam mantidos em segurança. Além disso, todos os aplicativos que acessem tais arquivos devem ter os privilégios adequados. Para maior proteção da segurança, as seguintes medidas precisam ser tomadas:
    • Use interfaces de administração seguras;
    • Armazene as informações de configuração em áreas de armazenamento seguras;
    • Qualquer dado sensível que está sendo armazenado em bases persistentes como seus resultados parciais devem ser atômicos - sempre delete se a transação for tanto bem-sucedida quanto quando falhar - Isso é especialmente útil para evitar que um atacante venha a tentar "quebrar" a aplicação para deixar o arquivo intermediário disponível para leitura.
    • Evita armazenar dados de configuração em cleartext.
    • Evite muitos administradores e múltiplas interfaces de administração.

    Gerenciamento de Sessões

    Partindo do princípio de que o protocolo HTTP é stateless, é necessário que se mantenha o estado das aplicações através de sessões. As informações de estado da sessão é transferida do browser em algum formato que sempre é devolvido para o servidor como o contexto do cliente. Esta informação do contexto é crítica para o gerenciamento da sessão e o estado do contexto da mesma. Se um adversário rouba o contexto e o usa em outro terminal dentro do período válido, é possível que ele possa roubar a sessão e assumir a identidade do usuário real.

    • Passe os identificadores da sessão apenas por canais criptografados;
    • Não permita sessões com tempo de vida muito prolongados
    • Não armazene o estado da sessão em um repositório inseguro - cuidado especial com a localização do arquivo ou tabela onde são armazenados os dados da sessão, pois se um atacante obtém acesso a eles, pode obter informações valiosas além do identificador da sessão em si.
    • Evite colocar o identificador de sessão em URLs.

    Estas medidas vão ajudar a evitar ataques como 'session hijacking', 'session replay', e 'man-in-the middle'.


    Code Injection

    No ambiente web, a maioria dos relatos de code injection são de códigos SQL aplicados com o intuito de obter acesso às bases de dados.

    • Aqui o atacante pode querer acesso a áreas que normalmente estão disponíveis apenas para usuários com outros níveis de acesso.
    • Podem querer também roubar informações importantes, como dados pessoais, dados bancários, de cartões de crédito e identificações de outros sistemas.
    • Em casos de espionagem industrial, o atacante pode querer adulterar a base de dados.
    • Por fim, um atacante pode tentar excluir completamente uma base de dados, causando DoS (Denial of Service - Negação de Serviço)

    A raiz de todos os problemas de code injection é que os desenvolvedores colocam muita confiança nos usuários das aplicações. Entretanto, nem todos os usuários na web farão o que o desenvolvedor da aplicação espera.

    Como exemplo, uma pessoa não precisa necessariamente de um browser para acessar a aplicação. De fato, um atacante experiente não usará um browser como o Internet Explorer ou Firefox: o atacante usará um navegador feito especificamente para toda a sorte de coisas ilícitas.

    Como arquiteto de segurança, você não deve nunca confiar no usuário, ou acreditar que ele está operando a aplicação de modo seguro e esperar que ele aja da forma como você deseja. Esta é uma vulnerabilidade relacionada com a programação da aplicação.


    Ataque Denial-of-Service (DoS)

    Em um ataque DoS, o atacante dispara diferentes ataques de segurança para encontrar uma aplicação ou serviço que não possa ser usado por usuários legitimados. Então, forçando o serviço a estar indisponível é considerado um ataque DoS. Isto pode ocorrer nas seguintes áreas:
    1. SO: Ele pode ser a nível de servidor, que está hospedando uma aplicação ou servidor web - o ataque pode ser centrado em alguma vulnerabilidade do sistema operacional, com o intuito de quebrá-lo.
    2. Protocolo: O ataque também pode ser focado no protocolo TCP/IP. Um ataque comum é o 'half open TCP', onde o buffer TCP é exaurido para disparar o ataque.
    3. Servidor Web: Pode ser em uma vulnerabilidade do servidor Web. Neste tipo de ataque, o atacante explora uma vulnerabilidade do servidor Web, como um IIS ou Apache.
    4. Aplicação: Pode ser uma vulnerabilidade da aplicação. Isso pode ser feito forçando a aplicação a entrar em looping, quebrar ou mesmo entrar em deadlock.
    As condições 1 a 3 não estão ligadas diretamente a codificação segura ou a arquitetura da aplicação. Entretanto, a condição 4 está diretamente relacionada com a segurança da arquitetura da aplicação. Está também relacionada com a programação para o ambiente web. Entretanto, se você debugar seu programa para garantir que não há buffer overflow ou processos em looping, você pode estar seguro.



    Tratamento de erros

    Para tornar o software mais amigável, nós geramos mensagens de erros mais acessíveis. De acordo com a prática de engenharia de software, é recomendado que as mensagens de erro sejam incluídas como parte do projeto. Além disso, tais mensagens devem ter significado claro e devem ser detalhadas. A filosofia por trás da mensagem de erro é que o usuário deve obter informações o suficiente para corrigir o erro e executar os próximos passos corretamente. As mensagens de erro possuem informações de alto-nível sobre o sistema, e isso é um risco em aplicações web;

    Geralmente atacantes deliberadamente entram com entradas incorretas para verificar o comportamento do sistema. Alguns campos são esperados que sejam preenchidos na interface do usuário; mensagens de erro detalhadas podem ajudar o atacante a conhecer o comportamento do programa. Portanto, enquanto você está projetando o sistema, você deve manter uma coisa em mente: você deve dar o mínimo possível, mas necessárias, informações nas mensagens de erro.



    Fonte: Architecting Secure Software Systems,