Felipe Weckx

Utilizando a nova API de hash de senhas do PHP 5.5

Introdução

O armazenamento de senhas de usuários de um sistema ou site é um assunto que nem sempre recebe a atenção necessária. Muitos armazenam a senha como texto puro ou utilizam métodos fracos de criptografia, gerando inúmeros casos de vazamento de senhas. Embora parte do problema seja a segurança do acesso aos servidores e bases de dados, devemos tentar sempre garantir que, uma vez com acesso aos dados o intruso não consiga obter o valor das senhas.

Para garantir que não seja possível obter o valor da senha de um usuário, mas ainda seja possível confirmar que a senha que o mesmo digitou é correta podemos utilizar uma função hash. Esta é uma função que à partir de um valor de entrada gera um valor de saída que não pode ser usado para restaurar o valor original, ou seja, é uma criptografia de mão única.

Por isto as funções de hash são tão boas para o armazenamento de senhas: uma vez criptografada a senha ninguém consegue saber qual era o seu valor original. Em teoria. Existem muitos algoritmos de funções hash como: MD5 e SHA1. O problema de utilizar estes algoritmos diretamente para criptografar a senha é que existem diversas bases de hashes pré calculados, por exemplo, vamos gerar um hash MD5 da senha:  felipe0111

Este script gera a saída:

Uma simples busca no Google pelo valor do hash já nos permite descobrir o valor da senha. Então não podemos utilizar simplesmente a função MD5 para gerar o hash. A função SHA1 é mais moderna, mas também existem diversas bases de hashes calculados.

API de hash de senhas do PHP

Para facilitar a vida dos desenvolvedores e prover uma forma segura de armazenamento de senhas o PHP 5.5 adicionou algumas novas funções específicas para o tratamento de senhas. Estas funções são muito práticas e úteis, podendo (e devendo) ser utilizadas em qualquer código de armazenamento de senhas de usuários.

A maior vantagem de utilizar estas funções é que, se utilizadas corretamente, as senhas são atualizadas automaticamente conforme algoritmos de hash mais seguros são criados, graças à constante PASSWORD_DEFAULT que refere-se sempre à função de hash recomendada.

Utilizando a API

Gerando o hash

O uso da API é bastante simples, basicamente utilizamos apenas as funções password_hash,  password_verifypassword_needs_rehash. Então, por exemplo, ao gravar a senha de um usuário no banco de dados devemos antes passar o valor pela função password_hash:

Bastante simples. Notem o uso da constante PASSWORD_DEFAULT esta é uma constante que pode ser alterada dependendo da versão do PHP e vai sempre ter o algoritmo de hash mais forte que o PHP tiver, então é importante que o local de armazenamento deste hash (ex: campo da base de dados) tenha um tamanho suficiente, com margem para crescimento.

Comparando o hash

Com a senha gravada como hash, podemos utilizar a função password_verify para verificar se um valor passado confere com o hash. É importante utilizar esta função para comparar pois, se o hash tiver sido gerado com um algoritmo diferente do atualmente configurado em PASSWORD_DEFAULT o hash não irá bater. A função password_verify automaticamente identifica o algoritmo utilizado e usa o mesmo para conferir.

Atualizando o hash com novo algoritmo

Outra vantagem da API de senhas do PHP é que podemos verificar se há um algoritmo mais forte para gerar o hash da senha. Ou seja, se numa versão nova do PHP for incluído um algoritmo de hash mais forte, a constante PASSWORD_DEFAULT terá seu valor alterado, mas nossas senhas permanecerão armazenadas com o algoritmo antigo. Isto não gera problemas na comparação com password_verify, mas pode tornar mais fácil a descoberta das senhas. Para isto há a função password_needs_rehash que indica se a senha precisa ser criptografada novamente:

Conclusão

A API de hash de senhas do PHP é uma ótima adição à linguagem, dando organização e um método de trabalho claro para lidar com o armazenamento e verificação de senhas. Com poucas funções ela organiza bem todo o fluxo de autenticação com senhas e ao utiliza-la podemos minimizar os dados causados por uma invasão ou vazamento de dados.

Streaming de videos com PHP

Vídeo para Web

Com o amplo suporte ao HTML5 nos navegadores mais modernos todos tem a capacidade de entender a tag <video>  que permite colocar o elemento na página, porém não é qualquer formato de vídeo que pode ser distribuído, já limitações de acordo com o navegador e sua versão. Então antes de colocar o vídeo na web precisamos convertê-lo para um formato suportado.

Formatos Suportados

O formato MP4 é o que hoje possui o suporte mais abrangente, mas uma das vantagens da tag <video> do HTML5 é permitir especificar diversos arquivos de vídeo, assim o navegador irá escolher automaticamente o arquivo com o formato suportado. De acordo com o site da W3Schools os formatos suportados para cada navegador são:

Navegador MP4 WebM Ogg
Internet Explorer SIM NÃO NÃO
Chrome SIM SIM SIM
Firefox NÃO SIM SIM
Safari SIM NÃO NÃO
Opera NÃO SIM SIM

Utilizaremos como exemplo este vídeo que está no formato Quicktime (.mov).  Para converter pode-se utilizar a ferramenta FFmpeg, disponível para Linux, Windows e MAC.

Convertendo para MP4

Para converter o vídeo para o formato MP4 podemos utilizar a linha de comando abaixo:

ffmpeg -i Rain_Fire.mov -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset slower -crf 23 -vf "scale=trunc(in_w/2)*2:trunc(in_h/2)*2" -movflags +faststart rain.mp4

Alguns parâmetros importantes do comando acima:

  • -c:v libx264 – Importante pois o codec x264 é o mais suportado
  • -pix_fmt yuv420p – Pixel format a utilizar
  • -profile:v baseline – Profile de vídeo. O baseline é para que o vídeo seja facilmente entendido em dispositivos Android
  • – preset slower – Determina a relação qualidade de vídeo/tempo de codificação. Pode ser diversos valores (faster, fast, medium, slow)
  • -crf 23 – Nível de qualidade do encoding 0 é sem perdas e 51 a pior qualidade possível. O valor de 23 é o padrão e pode ser omitido.
  • -vf “scale=trunc(in_w/2)*2:trunc(in_h/2)*2” – Por alguns motivos os vídeos MP4 encodados nesta forma devem ter os valores de largura e altura com números pares. Este parâmetro ajusta o tamanho do vídeo
  • -movflags +faststart – Faz com que os cabeçalhos de informação do vídeo sejam colocados no começo do arquivo, desta forma o navegador não precisa baixar o vídeo todo para saber qual o seu tamanho e formato. Este parâmetro é essencial para que possa ser feito o streaming do vídeo.

Para mais informações ver a documentação do FFmpeg sobre codificação de vídeos com H.264.

Convertendo para WebM

Outra possibilidade de formato de vídeo é o WebM, um formato recentemente adquirido pelo Google que o tornou de uso público. Para converter o vídeo para este formato podemos utilizar o comando abaixo:

ffmpeg -i Rain_Fire.mov -c:v libvpx -c:a libvorbis -pix_fmt yuv420p -b:v 2M -crf 5 rain.webm

De forma semelhante os parâmetros da conversão:

  • -c:v libvpx – o codec a utilizar para o video
  • -c:a libvorbis – o codec a utilizar para o áudio
  • -pix_fmt – formato de pixel
  • -b:v 2M – bitrate desejado. É importante definir este parâmetro pois o padrão não gera videos de boa qualidade
  • -crf 5 – Nível de qualidade do vídeo. Pode ser de 4 – 63. Quanto menor mais qualidade

Mais informações na documentação do FFmpeg.

Servindo o arquivo

Com os arquivos no formato correto podemos então criar nossa página para exibi-lo ao usuário. Vamos montar uma estrutura de diretórios da seguinte forma:

Estrutura de diretórios

Estrutura de diretórios

No diretório public ficarão os arquivos visíveis pelo servidor web e no diretório resource os arquivos de vídeo que iremos servir. No arquivo index.php está o HTML para a página e o arquivo stream.php será o responsável por ler os arquivos de vídeo e enviá-los ao navegador do usuário.

Streaming

O streaming é uma forma de distribuição de dados aonde o conteúdo é fornecido ao usuário conforme necessário, sem a necessidade de que ele receba todo o conteúdo para visualiza-lo. Esta é a melhor forma de servir vídeos pois permite a rápida visualização pelo usuário (ele não tem de esperar o download do vídeo todo) e também diminui a banda de rede utilizada pelo servidor. Os navegadores utilizam o cabeçalho HTTP Range para indicar qual parte do vídeo eles desejam que seja enviada. Assim se o usuário clicar na barra de navegação do vídeo o navegador envia uma nova requisição para o período respectivo.

Tratando o cabeçalho Range

Com o arquivo no formato correto podemos criar um script PHP para fazer a leitura do arquivo e envia-lo para o usuário. Porém precisamos considerar o cabeçalho Range para que sejam enviados somente os bytes que o navegador solicitou. De acordo com a RFC2616 que especifica o protocolo HTTP versão 1.1 o conteúdo do campo tem um dos seguintes formatos:

  • Os primeiros 500 bytes: bytes=0-499
  • O segundo lote de 500 bytes: bytes=500-999
  • Os últimos 500 bytes: bytes=-500
  • Todos os bytes à partir do byte 9500: bytes=9500-

O valor do campo vem na variável $_SERVER[‘HTTP_RANGE’] então podemos criar o código que irá ler o arquivo utilizando as funções de sistema de arquivos do PHP e colocar no arquivo stream.php:

É essencial tratar o cabeçalho Range quando estamos servindo arquivos que serão consumidos via streaming pois se não o usuário não conseguirá avançar/retroceder no vídeo  e terá de esperar o download completo do vídeo antes de começar a assisti-lo, o que é muito pouco prático para vídeos grandes.

A página web

Vamos agora criar o arquivo index.php que será acessado pelo usuário. Ele terá apenas o HTML necessário para a tag <video>:

Com o arquivo index.php criado podemos agora acessá-lo e ver o vídeo. Caso não queira utilizar um servidor web para testar pode-se utilizar o servidor web embutido do PHP executando:

php -S localhost:8000 index.php

E então acessar no navegador o endereço http://localhost:8000

 A tag <video>

A tag <video> é utilizada para inserir o vídeo na página. Dentro dela pode haver qualquer número de elementos <source> cada um deles indicando um formato de vídeo diferente ou até mesmo um arquivo de áudio. Então pode-se, por exemplo, colocar um arquivo de vídeo e um de áudio e o navegador vai “juntar” os dois na reprodução. No nosso caso especificamos dois elementos source, um com o vídeo no formato MP4 e outro com o vídeo no formato WebM. Desta forma o navegador vai escolher o que for suportado. Os atributos da tag são:

  • controls – Se devem ser exibidos os controles (avanço, retrocesso, volume, etc)
  • preload – Se o vídeo deve ser carregado juntamente com a página. Pode ser auto para carregar junto com página, metadata para o navegador carregar apenas os dados básico ou none para não carregar junto com página. O Internet Explorer não respeita este parâmetro.
  • width height – Largura e altura, respectivamente
  • poster – URL para uma imagem que será exibida no lugar do vídeo enquanto o mesmo não é carregado. Veja abaixo como gerar uma utilizando o FFmpeg.
  • autoplay – se especificado este parâmetro o vídeo irá começar a tocar assim que possível

Além destes diversos outros parâmetros estão disponíveis que permitem controlar o comportamento do vídeo.

Criando o poster

Como mostrado acima é possível especificar uma imagem que irá aparecer no lugar do vídeo enquanto este não for carregado. Podemos gerar esta imagem com o FFmpeg utilizando o comando abaixo:

ffmpeg -i Rain_Fire.mov -r 1 -vframes 1 -ss 0:05 poster.png

O parâmetro mais importante acima é o -ss 0:05 que especifica de qual momento será criada a imagem

Utilizando o video.js

A página acima funciona em qualquer navegador moderno que suporte HTML5. Mas e os navegadores mais antigos como Internet Explorer 7  e 8 que ainda são bastante utilizados? Para estes casos podemos utilizar a biblioteca video.js que faz automaticamente o fallback para um player em Flash caso o navegador não tenha suporte a HTML5. A utilização é bastante simples e há diversos exemplos no site. Segue a versão do nosso index.php utilizando a biblioteca:

 Conclusão

A tag <video> do HTML5 permite adicionar facilmente vídeos à paginas web, porém é necessário tomar cuidado com os formatos de vídeos suportados e fazer as conversões necessárias. É essencial que os arquivos sejam servidos via streaming para diminuir o tráfego de rede e melhorar a experiência do usuário e para tanto é essencial que o cabeçalho Range seja tratado de forma adequada, algo que pode ser feito facilmente pelo PHP. O código aqui mostrado tem apenas as funções básicas e pode com certeza ser muito melhorado.

O código de exemplo está disponível no Github: https://github.com/weckx/wcx-video-stream

Traduzindo mensagens de validação no ZF2

Ao criar formulários com Zend Framework 2 normalmente utilizamos o InputFilter para adicionar validações aos campos. Porém, por padrão as mensagens de validação vem em inglês, o que não é bom para sistemas que serão utilizados no Brasil. Para corrigir isto o ZF2 vem com uma grande quantidade de traduções das mensagens de validação padrão, entre elas o pt_BR. Para habilitar é bastante simples. Basta adicionar ao método onBootstrap do seu módulo o código abaixo:

O código acima deve ser colocado na classe Module dos módulos que você quer que sejam traduzidos, ou no módulo principal da aplicação para que seja executado em todos os controllers. É importante notar que como estamos instanciando no método onBootstrap o código será executado para todas as páginas acessadas, o ideal é alterar isto para que seja chamado apenas nos controllers que possuem formulários para evitar um processamento desnecessário.

 

PHP: in_array e arrays com valores true

Um detalhe muito importante da função in_array do PHP é o terceiro parâmetro $strict que por padrão tem o valor FALSE. Mas qual diferença exatamente ele faz? Vamos analisar o seguinte código:

A saída será simplesmente:

Porém, se adicionarmos ao array $array um item com o valor true:

A saída então será:

Ou seja, mesmo não havendo um item salmão no vetor $array a função in_array retornou true! Isto porque por padrão ela utiliza a comparação simples do PHP (ou “loose comparison”), ou seja, utilizando == (http://php.net/manual/en/types.comparisons.php) isto faz com que qualquer valor que não seja vazio ao ser comparado com true seja dado como igual. Isto pode causar um bug bastante difícil de rastrear já que o código a princípio funciona normalmente se for testado com arrays que não contenham o valor true. Para solucionar basta passar o terceiro parâmetro da função como true para que a função utilize a comparação estrita:

Com isto a comparação voltará a funcionar como esperado. Este é o tipo de erro que pode ser prevenido facilmente se o desenvolvimento for feito utilizando a metodologia TDD, mas se for feito sem pode ser realmente complicado de ser encontrado.

Enviando mensagens via syslog com PHP

O Syslog é um padrão de mensagens de log de aplicações utilizado por diversos tipos de equipamentos de computação como: servidores, impressoras, roteadores, firewalls, etc. A ideia principal é permitir que todos os logs gerados por uma ou mais aplicações possam ser enviados para um mesmo local, que pode ser no próprio equipamento ou em um servidor remoto.

Neste post vamos entender como funciona a mensagem Syslog e como criar uma classe simples de envio com o PHP.

Continuar lendo