Tanto o software de código aberto NGINX quanto o NGINX Plus são muito seguros e confiáveis como servidores web, proxies reversos e caches para seu conteúdo. Para proteção adicional contra acesso de clientes não autorizados, você pode usar diretivas do módulo Secure Link para exigir que os clientes incluam uma string com hash específica na URL do ativo que estão solicitando.
Nesta postagem do blog, discutiremos como configurar os dois métodos implementados no módulo Secure Link. Os snippets de configuração de exemplo protegem arquivos HTML e de lista de reprodução de mídia, mas podem ser aplicados a qualquer tipo de URL HTTP. Os métodos se aplicam tanto ao NGINX quanto ao NGINX Plus, mas por uma questão de brevidade, nos referiremos apenas ao NGINX Plus no restante do blog.
O módulo Secure Link verifica a validade de um recurso solicitado comparando uma string codificada na URL da solicitação HTTP com a string que ele calcula para essa solicitação. Se um link tiver uma vida útil limitada e o tempo tiver expirado, o link será considerado desatualizado. O status dessas verificações é capturado na variável $secure_link
e usado para controlar o fluxo de processamento.
Como mencionado, o módulo fornece dois métodos. Apenas um deles pode ser configurado em um determinado contexto http
, servidor
ou local
.
O primeiro e mais simples modo é habilitado pela diretiva secure_link_secret
. A sequência codificada é um hash MD5 calculado na concatenação de duas sequências de texto: a parte final da URL e uma palavra secreta definida na configuração do NGINX Plus. (Para obter detalhes sobre a primeira sequência de texto, consulte Usando URLs seguros básicos .)
Para acessar o recurso protegido, o cliente deve incluir o hash logo após o prefixo da URL, que é uma sequência arbitrária sem barras. Neste URL de exemplo, o prefixo é videos e o recurso protegido é o arquivo bunny.m3u8 :
/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8
Um caso de uso para esse método é quando um usuário carrega uma imagem ou documento em um servidor para compartilhamento, mas quer impedir que qualquer pessoa que saiba o nome do arquivo o acesse até que o link oficial seja publicado.
O segundo método, mais flexível, é habilitado pelas diretivas secure_link
e secure_link_md5
. Aqui, a string codificada é um hash MD5 de variáveis definidas no arquivo de configuração do NGINX Plus. Mais comumente, a variável $remote_addr
é incluída para restringir o acesso a um endereço IP de cliente específico, mas você pode usar outros valores, por exemplo $http_user_agent
, que captura o cabeçalho User-Agent
e, portanto, restringe o acesso a determinados navegadores.
Opcionalmente, você pode especificar uma data de expiração após a qual o URL não funcionará mais, mesmo que o hash esteja correto.
O cliente deve anexar o argumento md5 à URL da solicitação para especificar o hash. Se uma data de expiração for incluída na string que é hash, o cliente também deve anexar o argumento expires para especificar a data, como neste URL de exemplo para solicitar o arquivo protegido pricelist.html :
/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740
O módulo Secure Link está incluído em binários NGINX de código aberto pré-criados em nginx.org , nos pacotes NGINX fornecidos por fornecedores de sistemas operacionais e no NGINX Plus . Ele não é incluído por padrão quando você compila o NGINX a partir da fonte; habilite-o incluindo o argumento --with-http_secure_link_module
no comando configure
.
A maneira mais básica de proteger URLs é com a diretiva secure_link_secret
. No trecho de exemplo a seguir, protegemos um arquivo de lista de reprodução de mídia HTTP Live Streaming (HLS) chamado /bunny.m3u8 . Ele é armazenado no diretório /opt/secure/hls , mas é exposto aos clientes usando uma URL que começa com o prefixo videos .
servidor {
ouvir 80;
nome_do_servidor secure-link-demo;
localização /vídeos {
secure_link_secret enigma;
if ($secure_link = "") { return 403; }
reescrever ^ /secure/$secure_link;
}
localização /secure {
interno;
raiz /opt;
}
}
Com esta configuração, para acessar o arquivo /opt/secure/hls/bunny.m3u8 os clientes devem apresentar a seguinte URL:
/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8
A string com hash vem logo depois do prefixo, que é uma string arbitrária sem barras (aqui, vídeos ).
O hash é calculado em uma sequência de texto que concatena dois elementos:
secure_link_secret
, aqui enigma
.Se a URL de solicitação do cliente não tiver o hash correto, o NGINX Plus definirá a variável $secure_link
como a string vazia. O se
o teste falha e o NGINX Plus retorna o 403
Proibido
código de status na resposta HTTP.
Caso contrário (o que significa que o hash está correto), a diretiva de reescrita
reescreve a URL – em nosso exemplo para /secure/hls/bunny.m3u8 (a variável $secure_link
captura a parte da URL que segue o hash). URLs que começam com /secure são manipuladas pelo segundo bloco de localização
. A diretiva root
nesse bloco define /opt como o diretório raiz para arquivos solicitados e a diretiva internal
especifica que o bloco é usado somente para solicitações geradas internamente.
Para obter o hash MD5 em formato hexadecimal que o cliente deve incluir na URL, executamos o comando openssl
md5
com a opção -hex
:
# echo -n 'hls/bunny.m3u8enigma' | openssl md5 -hex (stdin)= 80e2dfecb5f54513ad4e2e6217d36fd4
Para uma discussão sobre a geração de hashes programaticamente, consulte Gerando o Hash Programaticamente .
Os comandos curl
de exemplo a seguir mostram como o servidor responde a diferentes URLs protegidas.
Se a URL incluir o hash MD5 correto, a resposta será200
OK
:
# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hls/bunny.m3u8 | head -n 1 HTTP/1.1 200 OK
Se o hash MD5 estiver incorreto, a resposta será403
Proibido
:
# curl -I http://secure-link-demo/videos/2c5e80de986b6fc80dd33e16cf824123/hls/bunny.m3u8 | head -n 1 HTTP/1.1 403 Proibido
Se o hash para bunny.m3u8 for usado para um arquivo diferente, a resposta também será403
Proibido
:
# curl -I http://secure-link-demo/videos/80e2dfecb5f54513ad4e2e6217d36fd4/hs/oven.m3u8 | head -n 1 HTTP/1.1 403 Proibido
O método mais flexível para proteger URLs usa as diretivas secure_link
e secure_link_md5
. Neste exemplo, nós os usamos para permitir acesso ao arquivo /var/www/files/pricelist.html somente de clientes no endereço IP 192.168.33.14 e somente até 31 de dezembro de 2016.
Nosso servidor virtual escuta na porta 80 e manipula todas as solicitações HTTP seguras no bloco de localização
/files
, onde a diretiva root
define /var/www como o diretório raiz para os arquivos solicitados.
A diretiva secure_link
define duas variáveis que capturam argumentos na URL da solicitação: $arg_md5
é definido como o valor do argumento md5 e $arg_expires
como o valor do argumento expires .
A diretiva secure_link_md5
define a expressão que é hash para gerar o valor MD5 para a solicitação; durante o processamento da URL, o hash é comparado ao valor de $arg_md5
. A expressão de exemplo aqui inclui o tempo de expiração passado na solicitação (capturado na variável $secure_link_expires
), a URL ( $uri
), o endereço IP do cliente ( $remote_addr
) e a palavra enigma
.
servidor {
ouvir 80;
nome_do_servidor secure-link-demo;
localização /arquivos {
raiz /var/www;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr enigma";
se ($secure_link = "") { retornar 403; }
se ($secure_link = "0") { retornar 410; }
}
}
Com esta configuração, para acessar /var/www/files/pricelist.html , um cliente com endereço IP 192.168.33.14 deve enviar esta URL de solicitação antes de Sat Dec 31 23:59:00 UTC 2016 :
/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740
Se o hash na URL enviada pelo cliente (capturado na variável $arg_md5
) não corresponder ao hash calculado pela diretiva secure_link_md5
, o NGINX Plus definirá a variável $secure_link
como a string vazia. O teste if
falha e o NGINX Plus retorna o403
Código de status proibido
na resposta HTTP.
Se os hashes corresponderem, mas o link tiver expirado, o NGINX Plus define o $link_seguro
variável para 0
; novamente o se
o teste falha, mas desta vez o NGINX Plus retorna o 410
Perdido
código de status na resposta HTTP.
Agora vamos ver como um cliente calcula os argumentos md5 e expires para incluir na URL.
O primeiro passo é determinar o equivalente de tempo Unix da data de expiração, porque esse valor está incluído na expressão com hash no formato da variável $secure_link_expires
. Para obter o horário Unix – o número de segundos desde Epoch (1970-01-01 00:00:00 UTC) – usamos o comando date
com a opção -d
e o especificador de formato +%s
.
Em nosso exemplo, estamos definindo o tempo de expiração para Sat Dec 31 23:59:00 UTC 2016 , então o comando é:
# data -d "2016-12-31 23:59" +%s1483228740
O cliente inclui esse valor como o argumento expires=1483228740 na URL da solicitação.
Agora executamos a string definida pela diretiva secure_link_md5
– $secure_link_expires$uri$remote_addr
enigma
– por meio de três comandos:
openssl
md5
com a opção -binary
gera o hash MD5 em formato binário.openssl
base64
aplica a codificação Base64 ao valor com hash.tr
substituem o sinal de mais ( +
) pelo hífen ( -
) e a barra ( /
) pelo sublinhado ( _
) e excluem o sinal de igual ( =
) do valor codificado.Para nosso exemplo, o comando completo é:
# echo -n '1483228740/files/pricelist.html192.168.33.14 enigma' | openssl md5 -binário | openssl base64 | tr +/ -_ | tr -d = AUEnXC7T-Tfv9WLsWbf-mw
O cliente inclui esse valor como o argumento md5=AUEnXC7T-Tfv9WLsWbf-mw no URL da solicitação.
Se o seu servidor web NGINX Plus estiver servindo conteúdo dinâmico de um servidor de aplicativos, tanto o NGINX Plus quanto o servidor de aplicativos precisarão usar o mesmo URL seguro. Você pode gerar o hash para o argumento md5 na URL programaticamente. A seguinte função do Node.js gera um hash correspondente ao definido no snippet de configuração do NGINX Plus acima. Ele aceita um tempo de expiração, URL, endereço IP do cliente e palavra secreta como argumentos e retorna o hash MD5 em formato binário codificado em Base64.
var crypto = require("crypto");
function generateSecurePathHash(expires, url, client_ip, secret) {
if (!expires || !url || !client_ip || !secret) {
return undefined;
}
var input = expires + url + client_ip + " " + secret;
var binaryHash = crypto.createHash("md5").update(input).digest();
var base64Value = new Buffer(binaryHash).toString('base64');
return base64Value.replace(/=/g, '').replace(/+/g, '-').replace(///g, '_');
}
Para calcular o hash do nosso exemplo atual, passamos estes argumentos:
generateSecurePathHash(nova Data('31/12/2016 23:59:00').getTime()), '/files/pricelist.html', “192.168.33.14”, "enigma");
Os comandos curl
de exemplo a seguir mostram como o servidor responde a URLs protegidas.
Se um cliente com endereço IP 192.168.33.14 incluir o hash MD5 correto e o tempo de expiração, a resposta será200
OK
:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 200 OK
Se um cliente com um endereço IP diferente enviar o mesmo URL, a resposta será403
Proibido
:
# curl -I --interface "192.168.33.33" 'http://secure-link-demo/files/pricelist.html?md5=AUEnXC7T-Tfv9WLsWbf-mw&expires=1483228740' | head -n 1 HTTP/1.1 403 Proibido
Se o valor hash do argumento md5 estiver incorreto, a resposta será403
Proibido
:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=qeUNjiY2FTIVMaXUsxG-7w&expires=1483228740' | head -n 1 HTTP/1.1 403 Proibido
Se a URL expirou (a data representada pelo argumento expires está no passado), a resposta é410
Perdido
:
# curl -I --interface "192.168.33.14" 'http://secure-link-demo/files/pricelist.html?md5=Z2rNva2InyVcRTlhqAkT4Q&expires=1467417540' | head -n 1 HTTP/1.1 410 Desaparecido
Aqui está outro exemplo de uma URL segura com data de expiração, usada para proteger tanto a lista de reprodução de um ativo de mídia quanto os arquivos de segmento.
Uma diferença do exemplo anterior é que adicionamos um bloco de configuração de mapa
aqui para remover a extensão da lista de reprodução (arquivo .m3u8 ) e dos segmentos HLS (arquivos .ts ) à medida que capturamos o nome do arquivo na variável $file_name
, que é passada para a diretiva secure_link_md5
. Isso serve para proteger solicitações para os segmentos .ts individuais, bem como para a lista de reprodução.
Outra diferença do primeiro exemplo é que incluímos a variável $http_user_agent
(que captura o cabeçalho User-Agent
) na diretiva secure_link_md5
, para restringir o acesso a clientes em navegadores específicos (por exemplo, para que a URL funcione no Safari, mas não no Chrome ou Firefox).
mapa $uri $file_name {
padrão nenhum;
"~*/s/(?<nome>.*).m3u8" $name;
"~*/s/(?<nome>.*).ts" $name;
}
servidor {
ouvir 80;
nome_servidor secure-link-demo;
localização /s {
raiz /opt;
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$file_name$http_user_agent enigma";
se ($secure_link = "") { retornar 403; }
se ($secure_link = "0") { retornar 410; }
}
}
O módulo Secure Link no NGINX permite que você proteja arquivos contra acesso não autorizado adicionando dados codificados, como o hash de uma parte específica do URL. Adicionar um tempo de expiração também limita a validade dos links, para maior segurança.
Para experimentar o NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso.
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."