domingo, 17 de abril de 2016

OWASP em Brasilia!


A nova liderança do capítulo da OWASP em Brasília convida para o primeiro evento de 2016 GRATUITO, de interesse de desenvolvedores, profissionais de segurança da informação, estudantes das áreas de computação e Tecnologia da Informação e demais interessados no assunto.

O 1° Encontro OWASP 2016 será um evento de Segurança da Informação, mais especificamente Segurança em Aplicações, que acontecerá no dia 04 de Junho de 2016
 em Brasília, DF. O evento contará com profissionais da área de Segurança da Informação de diversos Estados, como também diversos membros da OWASP. 

sexta-feira, 15 de abril de 2016

Login

Pergunta recorrente pelos desenvolvedores iniciantes, como desenvolver um login?
Esta é o primeiro muro que um desenvolvedor sofre ao se deparar com o Genexus, e muitas vezes a dificuldade não está na compreensão do processo em si, mas na escolha dos elementos necessários para realizar a operação.

Me desculpem os veteranos, mas no intuito de contribuir com os recém-nascidos, vamos responder isso de uma vez por todas, rs.

Use o GAM

A melhor opção que você poderá desenvolver é utilizando o GAM, pois é um recurso que já está disponível, foi desenvolvido mediante o protocolo OAUTH e protegerá todos os seus objetos expostos incluindo webservices.

Simples de utilizar, bastando nas Preferences ligar o Enable Integrated Security=Yes, em seguida trabalhar na configuração dos perfis (Roles) e usuários (Users).

O GAM poderá se comunicar com sistemas de login existentes por meio dos métodos de autenticação externa, que utilizará um webservice para conectar ao seu sistema remoto.

Maiores informações

Porque precisamos de Login?

Para os teimosos que pretendem escrever seus próprios mecanismos, vamos a uma estrutura básica.

Fazer login significa fornecer informações suficientes para que o script em execução no servidor possa identificar a pessoa que está utilizando o sistema. Desta forma será necessário ter algumas informações para que o controle possa ser efetuado. Previamente será necessário cadastrar as pessoas que serão identificadas, sendo que normalmente necessitamos de duas informações para proceder a identificação: usuário ou email e a senha. Uma transação serve a esta finalidade.
 

Algumas chaves possíveis para representar usuários:
  • Email: alguns sistemas utilizam email para identificar uma pessoa, o que não deixa de ser uma boa estratégia porém, muitas pessoas preferem ficar trocando de caixa de email de tempos em tempos, temos também pessoas que utilizam email de outra pessoa, como por exemplo, a namorada apaixonada que utiliza o email do namorado (acuado), claro que com primeiras intenções.
  • CPF: para os brasileiros temos o numero do CPF que também pode ser uma boa opção de chave, porém temos também algumas dificuldades, principalmente para pessoas que utilizam o CPF de terceiros (o filho que utiliza o CPF do pai ou do avô), e estrangeiros também não o possuem.
  • Palavras simples: apesar das críticas ainda acho que uma palavra definida pela própria pessoa seja a melhor estratégia para usuários. Colocando a palavra como chave primária teremos a garantia de que não será repetida, portanto, temos uma boa e livre opção.]
Teremos também a necessidade de identificar objetos (programas), perfis e associar tudo isso ao usuário.

 
 Veja que a complexidade vai aumentando, por isso a recomendação pelo GAM.

Processo de Login

Quanto uma pessoa utiliza um navegador de internet para se comunicar com um servidor Web se estabelece um registro da conexão que é a denominada chave de sessão. Trata-se de um valor randômico que inclui letras e números, único e que vai permitir entregar a comunicação de forma adequada para o requisitante.


A chave de sessão é criada  com ou sem operações de login, ou seja, é uma característica da Web, bastando chamar uma página ou script, que a mesma será criada. Localmente se criará um cookie e no servidor uma websession. Na imagem acima a chave é apresentada na variável Valor.

O servidor Web armazena esta chave em uma porção de memória chamada de websession, juntamente com outras informações que permitem estabelecer o contato com o cliente remoto. O endereço IP, e principalmente a data e hora da última comunicação com o servidor, de forma que depois de um certo tempo limite de inatividade (Time Session) o servidor pode destruir as sessões que expiraram (normalmente a sessão dura 20 minutos).

O processo de login normalmente utiliza o conceito do websession para armazenar alguma informação que determine que o cliente remoto passou pelo processo de identificação, para fins de controle de autorização para acesso aos objetos, normalmente o Perfil de acesso. A este perfil associa-se os objetos que possui privilégio de acesso, e por ai vai.

Operação de Login


A operação de login é simples, bastando um webpanel com duas variáveis e um botão.


E ao pressionamento do Confirm, a avaliação para saber se a pessoa informou corretamente os dois valores.

Event Enter
    &erro = ''
    for each
        where UsuarioId = &UsuarioId
        if UsuarioSenha <> &UsuarioSenha
            &erro = 'Senha incorreta'
        endif
    when none
        &erro = 'Usuário não encontrado'       
    endfor

    if &erro.IsEmpty()
        &websession.set('Usuario', &UsuarioId)
        Inicial()

    else
        msg(&erro)
    endif
Endevent


Observe que se o usuário e a senha estiverem corretos a página de ingresso no sistema Inicial(), será chamada, caso contrário a mensagem indicativa será exibida.

Na página Inicial() e em todos os objetos será necessário programar uma avaliação para se saber se existe alguma coisa registrada na variável Usuario na websession.

Event Start
    if &websession.get('Usuario').IsEmpty()
        Login()
    endif

Endevent






Esta é a estrutura mais básica que podemos construir. Falta ainda identificar o perfil, mas creio que daqui pra frente fica simples.

Considerações

Apesar da simplicidade temos muitas implicações relacionadas neste processo, recomendo inclusive que você estude um pouco a respeito da OWASP TOP 10, que trata dos problemas de vulnerabilidade que nossas aplicações poderão enfrentar.

  1. Recomenda-se que dados sensíveis como a própria senha do usuário seja gravada no banco em forma encriptada, praticamente dados pessoais devem sempre ser protegidos. Top A6: Exposição de dados sensíveis.
  2. A comunicação entre o navegador de internet e o servidor tem que ocorrer de forma encriptada por meio de um certificado SSL, e com protocolo HTTPS. Se não for desse jeito, qualquer pessoa poderá interceptar a comunicação e ler o usuário e senha transmitidas. Top A5 – Configuração Incorreta de Segurança, A2 – Quebra de autenticação e Gerenciamento de Sessão.
  3. Se não for avaliado o acesso em cada programa, e muitas vezes a verificação também tem que envolver os dados apresentados, estaremos quebrando mais um protocolo de segurança. Top A7 – Falta de Função para Controle do Nível de Acesso
  4. Normalmente nossas interfaces de login são submetidas a um mecanismo de invasão por força bruta onde um script busca criar as senhas para tentar ingressar. Deve haver um mecanismo de proteção para se evitar que sejam realizadas chamadas indiscriminadas em uma única chave de sessão. Uma estratégia é incluir um controle do tipo Captcha, para identificar um usuário humano. http://marketplace.genexus.com/product.aspx?captcha,en
  5. Os navegadores de internet tem a péssima funcionalidade de lembrar os valores de login. Se o procedimento não for corretamente implementado, poderá haver a possibilidade de um usuário ingressar no login de outro.
  6. Controles de segurança implementados em Javascript poderão ser facilmente quebrados, bastando o usuário desligar o privilégio de execução no seu navegador. Toda operação de segurança deverá ocorrer no servidor e não no cliente.

Poderíamos ficar discorrendo sobre esse assunto por várias páginas, mas acho que já deu pra dar uma noção. Eu particularmente acho que o GAM é a melhor solução, pois não precisaremos programar nada, e teremos mais tempo para desenvolver outras questões importantes relacionadas com segurança, que podem muitas vezes inviabilizar o sistema na web.

Este tema é profundo e requer não apenas atenção para se criar uma bela interface para realizar o login.

Bom trabalho!

sexta-feira, 8 de abril de 2016

Sobre Blob e Images

Carregar imagens diretamente no banco de dados é uma operação bastante interessante e prática utilizando os tipos Image e Blob no Genexus. Porém, quais as diferenças e até onde chegamos com esses dois recursos.

Parece até aquela briguinha manjada dos super heróis, aquela coisa meio armada das lutas de vale tudo dos anos 80. Falo isso porque os dois recursos são ótimos e não competem entre si, podem inclusive encontrar várias áreas em que se conectam, e cada um vai auxiliá-lo a desenvolver excelentes recursos.

Porém, antes de avançarmos, vamos revisar os artigos já apresentados sobre esses dois assuntos, aqui do Genexando.

Manipulando Imagens

  • http://www.genexando.com/2009/12/tratando-imagens.html
    Neste artigo chegamos a conclusão que o tipo Image nos ofereciam recursos que permitiam a carga da imagem, e principalmente sua posterior recuperação por meio do image.Link(), desta forma podemos ligar a imagem a um controle, ou programar o acesso por meio de <img src='...' >
  • http://www.genexando.com/2015_10_01_archive.html
    Neste artigo mais recente, falamos a respeito de resoluções, dimensões de imagens e também passamos rapidamente sobre o armazenamento com Blob e Image.

Manipulando Blob


O que devo escolher: Blob ou Image?

Apesar de diversos artigos ainda não tivemos um que respondesse definitivamente a respeito deste assunto. Ambos os tipos permitem armazenar dados binários no banco de dados. Então porque precisamos de dois tipos distintos? Qual é mais indicado em cada situação?

Image 

É destinado a armazernar e recuperar imagens, aceitando as extensões:  jpe, jpg, jpeg, gif, png, bmp, ico, svg, tif, tiff, ai, drw, pct, psp, xcf, psd, raw. Desta forma arquivos do tipo pdf, doc, xls, não serão aceitos.

É disponibilizado uma série de propriedades que facilitam a operação da imagem.


Image.FromURL()
Permite carregar uma imagem a partir de uma URL, bastando informar o local onde a mesma se encontra publicada, como por exemplo o logotipo do Genexando, que pode ser carregado em uma variável &image.

Event 'fromurl'
    &image.FromURL('http://1.bp.blogspot.com/-m1NiBb4VqsA/UXvcMgc9YpI/AAAAAAAAAsc/kUip66gYUGk/s1600/genexandologo.png')
Endevent


Image.FromImage()
Carrega uma imagem a partir de outra que já se encontra carregada na Kb, na área Customization - Images, como por exemplo a ActionExport, que representa um XLS.

Event 'fromimage'
    &image.FromImage(ActionExport)
Endevent


*** Inverti a ordem e coloquei uma URL em um FromImage e funcionou também, portanto, tanto FromImage como FromUrl aceitam imagens de URLs externas.


Image.ImageURI, Image.ImageName, Image.ImageType
Para quem precisa recuperar a imagem a partir de uma URL ou fisicamente no disco, é necessário compreender como a imagem carregada no BD se transforma novamente em um arquivo no servidor. Em nossa Kb temos uma pasta chamada PUBLICTEMPSTORAGE\MULTIMEDIA que é utilizada para construir os objetos temporários, como as imagens, por exemplo.

Image.ImageURI: devolve o caminho via servidor web até a imagem.
http://localhost/nomekb/PublicTempStorage/multimedia/nomekb_229a89cef51d48579586cdcf30d6ad85.png

Image.ImageName: devolve o nome da imagem, sem a extensão.
nomekb_229a89cef51d48579586cdcf30d6ad85

Image.ImageType: devolve o tipo ou extensão da imagem
png 
   
*** Se for necessário obter o caminho físico até a imagem, poderemos utilizar o caminho conhecido até a pasta PublicTempStorage\multimedia e acrescentar o ImageName e ImageType para completar.

Z:\Models\TESTE\EV3\Extensao\CSharpModel\web\PublicTempStorage\multimedia

*** Os valores ImageName, ImageType e ImageURI somente quando referenciarmos um atributo armazenado em uma tabela, isto devido a necessidade de se reconstruir a imagem em formato de arquivo físico novamente para ser devolvida para o navegador. Se a operação envolver apenas a carga de uma imagem em uma variável, a mesma ficará no somente no navegador, desta forma não teremos as informações até que ocorra a carga da imagem a partir do servidor, ou seja, a mesma for armazenada e posteriormente recuperada.

Blob

Blob é mais flexível em termos de carga pois aceitam qualquer tipo de arquivo, desde que se estabeleça um atributo para armazenar a extensão na propriedade File Type Attribute. Isto quer dizer se definirmos esta propriedade para um atributo do tipo Character(4), teremos a possibilidade de armazenar qualquer coisa, uma vez que para reconstruir o objeto a extensão será variável e recuperada deste atributo.

Assim como ocorre com as imagens os atributos do tipo Blob precisam se transformar novamente em arquivos físicos, para que possam ser enviados aos navegadores, e o mesmo é construido na pasta PUBLICTEMPSTORAGE. Com atributos do tipo Blob as informações não são tão explicitas quanto as definidas no tipo Image.

Blob.ToString() ou link(Blob)
A operação retorna o caminho físico até o arquivo reconstruído para ser devolvido ao navegador. Neste caso o nome do arquivo original não será mais considerado, sendo gerado novos arquivos aleatórios, abaixo um exemplo.

Z:\Models\TESTE\EV3\Extensao\CSharpModel\web\PublicTempStorage\usercontrol5863015.pdf

&URL = pathtourl(Blob)
Esta operação é meio obscura na documentação, mas muito importante pois devolve o link utilizado pelo navegador de internet para enviar o arquivo gerado pelo Genexus. Está documentada aqui http://wiki.genexus.com/commwiki/servlet/wiki?9563,PathToURL+function,. O resultado devolvido é algo semelhante ao apresentado a seguir.

http://localhost/nomekb/PublicTempStorage/usercontrol5863015.pdf



Tamanho do Blob: &File.GetLength()
Outra operação interessante que pode realizada no Blob e igualmente obscura na documentação é a obtenção da dimensão do Blob por meio de um tipo File, a operação GetLength() devolve a dimensão em bytes do arquivo. A documentação encontra-se aqui http://wiki.genexus.com/commwiki/servlet/wiki?6915,File+data+type,

&File.Source  = Blob.ToString()
&size = &File.GetLength()


Resultado:
12311

Tamanho do Blob: &File.GetName()
Utilizando o File também será possível obter o nome do arquivo gerado pelo Genexus. Com este nome também será possível chegar a URL da imagem.

&File.Source  = Blob.ToString()
&filename = &File.GetName()


Resultado:

usercontrol1740234.pdf

Base64 String

Os navegadores de internet conseguem entender um formato chamado Base64 String que representa uma imagem, porém codificada num chamado encode. Neste formato a imagem é gerada como uma string, no seguinte formato, apresentado de forma reduzida.

data:image/png;base64,iVBORw0KAACrQAAAmICA...WgA5ErkJggg==

O modelo foi implementado como uma maneira de reduzir a comunicação entre o servidor e o cliente, e não nos cabe aqui discutir o que é melhor ou pior, porque a imagem pode ser alcançada pela sua URI ou por uma string codificada no formato Base64.

A seguir alguma documentação sobre este tema:

Blob.FromBase64String()
Blob.ToBase64String()
Os Blobs incluem métodos que transformam uma string em Base64 em um Blob (Blob.FromBase64String()) ou um Blob em Base64 (Blob.ToBase64String()). Isso é interessante porque Image não possui este recurso, somente Blob.

Se for necessário uma Image neste formato é possível converter em Blob e utilizar o recurso da conversão Base64String().  Para isso será necessário que a Image e Blob sejam do mesmo tipo, ou seja, compartilhem do mesmo MIME type.

&Blob  = &Image
&string = &Blob.ToBase64String()

Ver documentação em http://wiki.genexus.com/commwiki/servlet/wiki?15204,Image+data+type

Redimensionamento?

Esta é uma boa pergunta, pois não temos como redimensionar a imagem quando realizamos o upload, e este é um fator muito importante visto que os aparelhos atuais geram imagens quase sempre desnecessariamente muito grandes. Imagens grandes muitas vezes não vão atender nossa necessidade na grande maioria dos casos, normalmente o que ser faz é reduzir a imagem a uma dimensão predeterminada.

Para smartdevices temos uma propriedade para escalar a imagem, Scale Type Property


Voltemos outra hora para tratarmos especificamente deste assunto.
 

terça-feira, 22 de março de 2016

Evolution 3 + Epplus= Excel

Já tratamos aqui diversas vezes a respeito do tema exportação de Excel por meio de bibliotecas externas como o Jakarta POI, SQL Lite. Também já informamos que o Genexus na versão X incluiu uma biblioteca chamada Epplus.DLL, que permite exportar sem que seja necessário realizar nenhuma ação adicional.

O detalhe é que para gerar Excel no Evolution 3 utilizando o Epplus é necessário definir a extensão do arquivo como XLSX e não XLS. Em caso de se utilizar a XLS o resultado é o travamento da interface e a não criação do arquivo.

Maiores informações em:

  • https://www.genexus.com/developers/websac?pt,,,27868;;