Home > Authentication 101, Best Practices, Code, PHP, Security, Series > Authentication 101 – Part 1 – Concepts

Authentication 101 – Part 1 – Concepts

Intro

Authentication always been one of the main concerns when developing web applications. This is a first post of a series of three (that’s what I’ve initially planned, I may extend it)that tries to shed some light on this subject. Although all examples in this series are presented using PHP and PostgreSQL, you’ll notice that the concepts involved are pretty common to other web technologies as well.

Part 1 – Concepts

I always liked to think before doing something or, in the worst case, think while doing it. Both strategies work for me, although the second one always requires more time re-coding everything =) The important thing here, and this is commonly overlooked in most development environments I’ve watched in almost 15 years working on the web, is to define which are the concepts involved in authenticating a user, how the application (or, at least this part of the application) should flow.

In fig. 1 we can see what I’ve came up as the basic flow of a reasonably secure authentication process:

Fig. 1 - Authentication flowchart

Fig. 1 - Authentication flowchart

Let’s break down this flowchart into parts and take an in-depth look on everything, from basic to “not-so-basic”:

  1. The first step is, obviously, to render a form so the user can enter his credentials (meaning, his login and password).
  2. The second step is to verify if our user has entered the correct login/password combination. There’s a few things to note here, that became increasingly – and surprisingly – more popular in today web applications:Today web applications are forgetting what the term “Access Credentials” mean. Most web applications we use nowadays (Google, Twitter, you name it) doesn’t require a confidential pair of credentials anymore: the login is usually well known by the general public – being a part of an e-mail address (e.g.: Google) or part of a friendly URL (e.g.: Twitter). This basically means people are beginning to develop their applications with half the security required for an authentication system: The only obscure part is the password, the login is out in the open, and often even published by the user himself on many resources all over the web.

    Correct, secure applications require a pair of credentials: login AND password. The login can even be chosen by the user and even more mean something “friendly” to him, but it must not be disclosed to the general public. Going even further – we’ll see that on parts 2 and 3 – not only the password, but also the login part of the credential must be encrypted. It’s really hard to think that no one can realize the obvious security advantages on this approach: you have two unknown data strings that must be guessed. They are both encrypted and completely obscure (you don’t know, for an example, how long is any of the strings in hand).

  3. The next two steps are also (less) commonly overlooked: In case our user got his credentials right we must check to see if there is a session already active for him. In case there is, we must end the process. There are (basically) two ways of ending it: we either disconnect the previous session and let the new one pass or we block the user entirely and implement a way so the “real” user can change his password immediately so he can authenticate himself later.Although it may seem like a rude way to deal with the problem, this actually uncovers another common problem in web applications these days: the fear of “complicating the user experience”.

    This actually covers a lot of reasons, but none of them are really valid from security’s point of view. One of them is assuming the user is ignorant and that he gave away his credentials willingly to a friend, for an example. This concept is so absurd that it’s annoying to address, but hey, it’s a dirty job, but someone gotta do it: Access credentials are like real world IDs. You don’t give your ID card to a friend, so why would you give away your access credentials? In the real world impersonating someone else is a crime so everyone is afraid of doing such a thing. Problem with web applications is that no one tells the user it’s wrong and give him a “slap in the wrist”, so he keeps doing it. Keep treating the user as an ignorant child and he will remain an ignorant child.

  4. In case the user got his access credentials wrong we must implement a well known security check. Yes, it’s well known, but hardly used: we must check how many times this user is trying to authenticate himself in a reasonably short period of time. In the case he exceeds a reasonable number of wrong attempts in a reasonable time frame we must at least freeze his account so he can’t keep trying.  This must be done not only to prevent brute forcing attacks, but also because authentication attempts consume resources: memory, CPU, database access, etc… Once again, the web lacks the good sense we (usually) find in the real world: No one keeps kicking a door for half an hour, so why should you let people bang on your application’s door over and over?

    Now that we’ve got the concepts, we will, in the next articles of this series, get our hands dirty and begin to see how to implement this both in our storage layer (database) as in our code. See ya there!

Introdução

Autenticação sempre foi uma das maiores preocupações quando se desenvolve uma aplicação web. Este é o primeiro de uma série de três (isso foi o que planejei inicialmente, é possível que eu estenda isso) que procura lançar alguma luz no assunto. Embora todos os exemplos desta série sejam apresentados usando PHP e PostgreSQL, você perceberá que os conceitos envolvidos são bem comuns para outras tecnologias web também.

Parte 1 – Conceitos

Eu sempre gostei de pensar antes de fazer alguma coisa, ou, no pior caso, pensar enquanto eu faço. Ambas as estratégias funcionam pra mim, embora a segunda sempre demande mais tempo re-codificando tudo =) O que é importante aqui, e que é normalmente deixado de lado na maioria dos ambientes de desenvolvimento que conheci nesses quase 15 anos trabalhando com a wev, é definir quais conceitos estão envolvidos em autenticar um usuário, como deve ser o fluxo da aplicação (ou pelo menos dessa parte da aplicação).

Na figura 1 vemos o que eu defini como o fluxo básico de um processo de autenticação razoavelmente seguro:

Fig. 1: O fluxo da autenticação

Fig. 1: O fluxo da autenticação

Vamos quebrar esse diagrama de fluxo em partes e dar uma olhada em profundidade em tudo, desde o básico até o “não-tão-básico”:

  1. O primeiro passo é, obviamente, renderizar um formulário para que o usuário possa entrar com suas credenciais (ou seja, login e senha).
  2. O segundo passo é verificar se nosso usuário entrou com a combinação correta de login e senha. Existem algumas questões a se notar aqui, que estão se tornando cada vez mais – surpreendentemente – populares nas aplicações web de hoje:As aplicações web de hoje estão se esquecendo do que o termo “Credenciais de Acesso” significa. A maioria das aplicações web que usamos hoje em dia (Google, Twitter, etc…) não requerem mais um par confidencial de credenciais: o login é normalmente bem conhecido pelo público em geral – sendo parte de um endereço de e-mail (p. ex.: Google) ou parte de uma URL amigável (p. ex.: Twitter). Isso basicamente significa que as pessoas estão começando a desenvolver suas aplicações com metade da segurança requerida por um sistema de autenticação: a única parte obscura é a senha, o login está disponível para o público, e é normalmente divulgado pelo próprio usuário em muitos lugares na web.

    Aplicações seguras e corretas requerem um par de credenciais: login E senha. O login até pode ser escolhido pelo usuário e ainda mais, significar algo amigável para ele, mas não pode ser disponibilizado para o público em geral.Indo mais longe – veremos isso nas partes 2 e 3 – não apenas a senha, mas também a parte da credencial referente ao login deve ser criptografado. É muito difícil imaginar que ninguém se dê conta das vantagens óbvias de segurança nesta abordagem: você tem duas strings de dados que são desconhecidas e precisam ser advinhadas. Ambas são criptografadas e completamente obscuras (você não sabe por exemplo o tamanho de cada string).

  3. Os dois próximos passos também são normalmente (menos) deixados de lado: No caso de nosso usuário acertar as credenciais devemos checar se existe uma sessão já ativa para ele. Caso positivo nós precisamos encerrar o processo. Há (basicamente) duas  formas de encerrá-lo: Ou desconectamos a sessão anterior e deixamos a nova passar ou bloqueamos completamente o usuário e implementamos uma forma para que o usuário “verdadeiro” possa trocar sua senha e se autenticar novamente mais tarde.Embora essa pareça uma forma rude de lidar com o problema, isto na verdade mostra outro problema comum nas aplicações web de hoje: o medo de “complicar a vida do usuário”.

    Na realidade isso se deve a uma série de razões, mas nenhuma delas é válida do ponto de vista de segurança. Uma delas é se assumir que o usuário é ignorante e liberou propositalmente suas credenciais para um amigo, por exemplo. Esse conceito é tão absurdo que chega a ser chato de se falar, mas hei, é um trabalho sujo, mas alguém tem que fazê-lo: Credenciais de Acesso são como carteiras de identidade do mundo real. Você não libera sua carteira de identidade para um amigo, então porque fazer o mesmo com as suas credenciais? No mundo real se passar por outra pessoa é crime, então as pessoas têm medo de fazê-lo. O problema com as aplicações web é que ninguém diz pro usuário que isso é errado e dá um “tapinha na sua mão”, então ele continua fazendo. Continue tratando o usuário como uma criança ignorante e ele permanecerá sendo uma criança ignorante.

  4. No caso do usuário errar as suas credenciais de acesso, precisamos implementar uma checagem de segurança bem conhecida. Sim, é bem conhecida, mas raramente utilizada: precisamos checar quantas vezes o usuário está tentando se autenticar em um período razoavelmente curto de tempo. No caso dele exceder um número razoável de tentativas em um período razoável de tempo, precisamos pelo menos congelar a sua conta, para que ele não continue tentando. Isso precisa ser feito não apenas para evitar ataques de força bruta, mas também porque tentativas de autenticação consomem recursos: memória, CPU, acessos à base de dados, etc… Uma vez mais a web carece do bom senso que (normalmente) encontramos no mundo real: Ninguém fica chutando uma porta durante meia hora, então porque devemos permitir que as pessoas fiquem dando porradas na porta da nossa aplicação o tempo todo?

    Agora que temos os conceitos, vamos, nos próximos artigos desta série, sujar nossas mãos e ver como implementar isso tanto na camada de armazanamento (banco de dados), como no nosso código. Vejo você lá!

  1. Ricardo
    August 26th, 2009 at 11:12 | #1

    O Blogroll está duplicado na coluna ao lado :)

  2. August 28th, 2009 at 00:08 | #2

    Obrigado por avisar, Ricardo. Já vou resolver :)

  1. January 11th, 2011 at 13:02 | #1