Jump to content

Archived

This topic is now archived and is closed to further replies.

Pita

Rest e Segurança

Recommended Posts

Olá Pessoal,

 

Estou começando a pesquisar sobre Rest para tentar encontrar uma solução para ambientes multidevice (desktop, smartfone, tablet, etc). Vou contar uma historinha para que vocês entendam meu objetivo:

 

No passado a principal forma de acessar informações online, as pessoas abriam o navegador e acessavam um site por exemplo, a principal preocupação do desenvolvedor era se o site funcionava no navegador, ou navegadores.

 

O tempo foi passando e apareceram os smartphones, e as pessoas começaram a acessar os sites dos seus celulares e suas telas pequenas, com isso os desenvolvedores começaram a precisar fazer layouts que funcionem tanto no desktop quanto no celular. Observe que aqui começamos a fazer ajustes somente na camada de apresentação, o resto do site continua basicamente o mesmo. Para ajudar nisso surgiu o MVC, etc...

 

O tempo passou mais um pouco, os Apps ficaram famosos, e as empresas começaram a solicitar Apps(IPhone ou Android) para que seus clientes instalem em seus smartphones. Observe que agora não estamos mais falando somente de navegador, agora estamos tendo uma aplicação para o site(navegador), outra aplicação para o IPhone, outra para o Android, etc.

 

Fim da historia. O que quero dizer, está vai ficar complicado ter tantas aplicações, principalmente porque existe muita coisa em comum, já que as regras de negócio precisam ser a mesma para todas.

 

Pesquisei e achei o Rest, idéia muito legal. Poderia ter uma aplicação/qqcoisa com as regras de negócio, o site e Apps seriam apenas interfaces para a aplicação. Se no futuro aparecer um gadget novo, é só fazer uma nova "interface" que as regras já estarão implementadas, mudar a regra nao precisa mudar todas as interfaces(site, IPhone, Android, etc), ou muda muita pouca coisa, etc. Tudo muito lindo.

 

Agora minha dúvida, como funciona a segurança disso tudo? Em um site normal, o site sabe quem está logado porque ele passou os dados no início e ficou armazenado na session/coockie/qqlugar, mas no modelo usando Rest, quem acessa a aplicação não é um usuário, e sim um site/IPhone/Android/seiláoque.

 

 

Olha um modelo simples para entender:

Usuário <=> Interface(Site ou App) <=> Aplicação de negocio(+banco de dados)

Como minha aplicação de negocio controla isso? Pergunto porque no Rest o acesso é feito via HTTP e não queremos que o usuário, ou algum outro espertinho, tente acessar a Aplicação de negocio diretamente. Quais questões de segurança preciso levar em consideração? O que o pessoal normalmente faz, etc.

 

Obrigado pela ajuda

Share this post


Link to post
Share on other sites

Esse é um assunto muito extenso porque é praticamente todo baseado no protocolo HTTP que é assustadoramente grande.

Mas, numa tradução bem livre, ReST significa fazer alguma coisa, de uma certa forma, com alguma coisa, sendo todos os participantes envolvidos no processo conhecido pela URL de acesso. Já a forma de requisição ao serviço influencia nas decisões da aplicação.

E justamente por essas características é que é possível automatizar e simplificar a aplicação através de roteamento de requisições.

Por exemplo:

:seta: site.com/admin/users/update/id/1

Conhecemos os participantes. Só de ver a URL sabemos que queremos gerenciar (admin) os usuários (users), atualizando (update) aquele de id = 1.

 

Numa requisição GET, isso faria retornar um Template View com o formulário de atualização preenchido com os valores atuais ao passo que a mesma URL numa requisição POST executa a ação de atualização e retorna um Template View informando o sucesso ou fracasso.

Mas você quer enriquecer sua aplicação e permitir que os dados sejam atualizados a partir de sua própria listagem, com AJAX. Você não vai enviar a requisição e trazer um HTML inteiro como resposta, navegar em dezenas de nós aninhados para fazer um simples inline edit.

Bastaria para isso que a requisição fosse roteada com um argumento específico, por exemplo, /output/json. Você montaria uma estrutura JSON com as informações mais importantes par que a aplicação continue e retorna.

Seu sistema vai ser consumido por uma App desktop que por infortúnio não pode manipular JSON? Tudo bem, ofereça um XML roteando esse tipo de resposta caso a URL contenha /output/xml.

Existem serviços que preferem não adicionar um parâmetro adicional e sim uma extensão. Eu até acho mais elegante e transparente ao usuário curioso que fuça no código fonte sem motivo algum.

Share this post


Link to post
Share on other sites

A url não deve ser responsável pelo formato do output, da linguagem de exibição, encoding, etc, o HTTP tem vários headers Accept, como por exemplo: Accept-Charset, Accept-Encoding, Accept-Language.

 

E também não deve ser responsável pela "ação":

 

 


:seta: site.com/admin/users/update/id/1

 

Quando você for fazer um update basta requisitar com PUT:

 

Por exemplo:

 

MÁ PRÁTICA:

 

site.com/admin/users/get/id/1

site.com/admin/users/create

site.com/admin/users/update/id/1

site.com/admin/users/delete/id/1

 

BOA PRÁTICA:

 

use os métodos do HTTP para identificar a ação:

 

GET site.com/admin/users/id/1

POST site.com/admin/users

PUT site.com/admin/users/id/1

DELETE site.com/admin/users/id/1

 

E a URL é baseada em hierarquia, logo:

 

/id/1 não faz sentido!

 

use simplesmente:

 

 

GET site.com/admin/users/1 - recupera o usuário com o id 1

POST site.com/admin/users - cria um usuário

PUT site.com/admin/users/1 - atualiza o usuário

DELETE site.com/admin/users/1 - apaga o usuário com o id 1

 

E nunca faça isso, por exemplo:

 

site.com/admin/users/1.json

site.com/pt-br/admin/users/1

site.com/utf-8/admin/users/1

 

Use os Accept-* nos headers da requisição

 

Esse slide é interessante: http://www.slideshare.net/Alganet/rest-key

 

E algo muito, mas muito importante: jamais use cookies ou sessions em uma API REST, já que REST é stateless.

Share this post


Link to post
Share on other sites

Legal os comentários,

Sei que o assunto é extenso, por isso acho válido a gente discutir sobre ele.

 

Vamos supor um caso de criação de usuário, vamos supor que minha aplicação interface(um site) faz uma requisição POST site.com/admins/users, passando os dados do usuário via JSON.

 

Como minha aplicação de negócio tem segurança da origem das informações?

 

No JSON trocado entre a aplicação interface e a aplicação de negócio poderíamos ter um hash para garantir que ninguém quer enganar a aplicação de negócio?

Share this post


Link to post
Share on other sites

Você não queria que eu explodisse o cara logo no primeiro tiro né? :P

 

Você disse que /id/1 não faz sentido. Certo, você imaginou o quão limitado seria esse serviço por restringir a consulta à somente o ID do usuário? Ou o quão sobrecarregada ficaria a ação responsável por essa requisição caso viesse a fornecer a opção de buscar por ID ou por nome sem "violar" a hierarquia da URL?

 

Isso sem contar o fato de que, salvo engano, PUT e DELETE não podem ter Response Body dificultando o retorno positivo/negativo para o usuário.

 

Fora os cabeçalhos específicos requeridos por tais métodos de requisição.

 

Sobre o Accept-*, até hoje não vi nenhum servidor que respondesse application/json.

 

E mais, o entendimento que eu tenho desses cabeçalhos, de acordo com a RFC 2616 Section 14.14 é a de especificar os tipos de resposta aceitos pela requisição. Mas muitos servidores mal configurados erram feio do quality factor fazendo com que uma aplicação que confie em tal diretriz, entregue o formato errado para o cliente operar.

 

Quanto a resposta que acabou de chegar (eu adorei esse recurso :grin:), esse problema me parece que se resolve com OAuth, onde registra-se uma aplicação no site da API e este fornece duas chaves para que a aplicação consumidora se autentique.

 

Apesar de conceitualmente parecer uma coisa fácil (receber, consultar, liberar ou negar) a especificação OAuth é bem mais complexa e talvez seja por isso que algumas APIs são mais fáceis de trabalhar do que outras, a exemplo o Tumblr vs. ImgUr.

Share this post


Link to post
Share on other sites

Você não queria que eu explodisse o cara logo no primeiro tiro né? :P

 

Não, mas é bom sempre ressaltar hehe.

 

 

 

Você disse que /id/1 não faz sentido. Certo, você imaginou o quão limitado seria esse serviço por restringir a consulta à somente o ID do usuário? Ou o quão sobrecarregada ficaria a ação responsável por essa requisição caso viesse a fornecer a opção de buscar por ID ou por nome sem "violar" a hierarquia da URL?

 

URLs devem ser únicas. Você só deve ter uma URL para cada coisa. E também não esqueceremos a filosofia da URI: "cool urls don't change"

 

 

 

Isso sem contar o fato de que, salvo engano, PUT e DELETE não podem ter Response Body dificultando o retorno positivo/negativo para o usuário.

 

Fora os cabeçalhos específicos requeridos por tais métodos de requisição.

 

Mas uma API não é feita para browsers, para usuários, e sim para as apps que irão consumir (seja um site, app mobile, whatever). Esta é a grande vantagem, e por isso é muito falado que MVC não é o "cara".

 

Responses de API geralmente são em branco: o código HTTP fala mais que mil linhas de output.

 

Validação dos dados enviados não passou: status 400

Usuário não passou na autenticação: 401

Deu certo, tome uma response: 200

etc etc, no slide que estava no post anterior tem mais exemplos.

 

Por exemplo, em um site, teríamos a API e o site. O site pode ser feito em Flex, Flash, PHP fazendo request na API e jogando para uma view, ou o melhor, html, com javascript acessando a API via ajax (hoje é possível ajax SEO-friendly), fica animal.

 

 

 

Sobre o Accept-*, até hoje não vi nenhum servidor que respondesse application/json.

 

Ela pode responser json, xml, yaml, LOLCODE, etc.

 

Os Accept-* são todos cabeçalhos inseridos na request. Essa página da wikipédia me ajudou a aprender (http://en.wikipedia.org/wiki/List_of_HTTP_header_fields).

 

 

 

E mais, o entendimento que eu tenho desses cabeçalhos, de acordo com a RFC 2616 Section 14.14 é a de especificar os tipos de resposta aceitos pela requisição. Mas muitos servidores mal configurados erram feio do quality factor fazendo com que uma aplicação que confie em tal diretriz, entregue o formato errado para o cliente operar.

 

 

Mas quem sabe o que vai retornar é seu PHP, via $_SERVER['HTTP_ACCEPT'], se o servidor estiver mal configurado, precisa configurar direito, curto e direto

 

Quanto a resposta que acabou de chegar (eu adorei esse recurso :grin:), esse problema me parece que se resolve com OAuth, onde registra-se uma aplicação no site da API e este fornece duas chaves para que a aplicação consumidora se autentique.

 

oAuth não é a única forma, temos outras, dependendo do caso, mais simples e melhores.

 

 

 

Apesar de conceitualmente parecer uma coisa fácil (receber, consultar, liberar ou negar) a especificação OAuth é bem mais complexa e talvez seja por isso que algumas APIs são mais fáceis de trabalhar do que outras, a exemplo o Tumblr vs. ImgUr.

 

Mais fácil não significa melhor, semântica acima de tudo. Existem REST patterns não para enfeitar, mas sim para serem seguidas.

 

O ponto principal é que uma API ela não é feita para browser acessar, acho que daí começa a confusão, o maldito do Rails induz a este erro (e a vários outros kk).

Share this post


Link to post
Share on other sites

Não, mas é bom sempre ressaltar hehe.

 

O exemplo incicial foi bem leve, de uma API fictícia que não confia cegamente nos métodos corretos e nem sempre provê os cabeçalhos adequados.

 

URLs devem ser únicas. Você só deve ter uma URL para cada coisa. E também não esqueceremos a filosofia da URI: "cool urls don't change"

 

Depois que respondi fiquei aqui pensando e de fato faz sentido. A aplicação cresce um pouco mais do que o inicialmente planejado mas fica mais sólido.

 

Mas uma API não é feita para browsers, para usuários, e sim para as apps que irão consumir (seja um site, app mobile, whatever). Esta é a grande vantagem, e por isso é muito falado que MVC não é o "cara".

 

Por exemplo, em um site, teríamos a API e o site. O site pode ser feito em Flex, Flash, PHP fazendo request na API e jogando para uma view, ou o melhor, html, com javascript acessando a API via ajax (hoje é possível ajax SEO-friendly), fica animal.

 

Separei esse pra ficar melhor. Confesso que nunca imaginei uma aplicação consumindo sua própria API. É realmente vantajoso mas, talvez por nunca ter considerado esse cenário, me vejo com poucas opções de montar a View de um usuário diferente da resposta de um programador-consumidor.

 

Quanto a todo consumo rodar via JavaScript isso acho que acabaria sendo um impasse em termos de performance. Mas é algo a se ver com carinho.

 

Ela pode responser json, xml, yaml, LOLCODE, etc.

 

Os Accept-* são todos cabeçalhos inseridos na request. Essa página da wikipédia me ajudou a aprender (http://en.wikipedia.org/wiki/List_of_HTTP_header_fields).

 

Você não tem idéia de como eu me debrucei sobre essas definições uns meses atrás... :cry:

 

Mas quem sabe o que vai retornar é seu PHP, via $_SERVER['HTTP_ACCEPT'], se o servidor estiver mal configurado, precisa configurar direito, curto e direto

 

Ah! Claro! Como se a vida de um programador você um lindo conto de fadas assim. :lol:

 

oAuth não é a única forma, temos outras, dependendo do caso, mais simples e melhores.

 

De fato. Mas stateless nem tantas assim.

 

Mais fácil não significa melhor, semântica acima de tudo. Existem REST patterns não para enfeitar, mas sim para serem seguidas.

 

O ponto principal é que uma API ela não é feita para browser acessar, acho que daí começa a confusão, o maldito do Rails induz a este erro (e a vários outros kk).

 

Discordo parcialmente de você nesse ponto. O pessoal do ImgUr complicou demais o processo de autenticação. Eu experimentei diversas implementações e com nenhuma delas consegui consumir a API de forma decente.

 

Talvez porque eles tenham seguido demais o padrão.

 

Já o Tumblr segue o padrão? Segue. Mas não se estende à usar requisições PUT/DELETE quando um POST resolve perfeitamente.

 

Existe autenticação via OAuth? Existe. Mas eles "violam" parte da hierarquia por oferecer um parâmetro que, quando preenchido com a chave secreta permite você consumir de forma N vezes mais fácil.

Share this post


Link to post
Share on other sites

Separei esse pra ficar melhor. Confesso que nunca imaginei uma aplicação consumindo sua própria API. É realmente vantajoso mas, talvez por nunca ter considerado esse cenário, me vejo com poucas opções de montar a View de um usuário diferente da resposta de um programador-consumidor.

 

Quanto a todo consumo rodar via JavaScript isso acho que acabaria sendo um impasse em termos de performance. Mas é algo a se ver com carinho.

 

É uma maravilha a app consumir sua própria API, é a verdadeira separação de camadas. Você não vai ter uma linha de PHP nas views, o front não vai se estressar, tudo que ele precisará saber é o protocolo HTTP (obrigação de todo dev. web, seja back, front).

 

Não fica lento, o facebook faz isso direto, não vai ser tão rápido, vai ser em uma velocidade igual como se você estivesse carregando uma página, mas a vantagem é que você só carrega a API, e não todo o CSS, a maioria das imagens, etc.

 

Ah! Claro! Como se a vida de um programador você um lindo conto de fadas assim. :lol:

 

Pode ser, esses erros desse tipo não é tão comum, é comum nos hosts de 1 real dos sobrinhos, ou convence o chefe/cliente :natalbiggrin: ou "gambiarreia" :upset: .

 

 

De fato. Mas stateless nem tantas assim.

 

É, temos autenticação HTTP, mas temos o gambiarrão, de passar username e usuário via query string.

 

Aí que vem a parte que eu acho interessante da app consumir API, a API pode somente ter uma pagina de login check, retornando 401 se o usuario passado não existe, se ele existir, vc cria cookie javascript e para cada ação que necessite de auth na API vc usa os valores do cookie.

 

Ou seja:

 

API stateless

App stateful

 

E melhor ainda, implementando uma CDN.

 

E sempre sua app terá cookies, todo mundo precisa de Google Analytics, ele usa cookies, mas a API não pode ser stateful.

 

 

 

Discordo parcialmente de você nesse ponto. O pessoal do ImgUr complicou demais o processo de autenticação. Eu experimentei diversas implementações e com nenhuma delas consegui consumir a API de forma decente.

 

Talvez porque eles tenham seguido demais o padrão.

 

Já o Tumblr segue o padrão? Segue. Mas não se estende à usar requisições PUT/DELETE quando um POST resolve perfeitamente.

 

Existe autenticação via OAuth? Existe. Mas eles "violam" parte da hierarquia por oferecer um parâmetro que, quando preenchido com a chave secreta permite você consumir de forma N vezes mais fácil.

 

Qual o problema de PUT/DELETE, eu via eles também como vilões, mas quando você usa realmente o esquema de API desacoplada da app e a app tendo uma boa ferramenta de Request (jQuery tem uma excelente), não há problemas, o que não pode se pensar é que o formulário html vai direto para a API, aí ferrou tudo e vc entrou no conceito "Rails" (realmente eu odeio esse tal kkk).

Share this post


Link to post
Share on other sites

×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.