Publicação
Security and Usability in the HeadREST Language
| Resumo: | Actualmente, observa-se o crescimento contínuo de serviços web, sem sinais de abrandar. As trocas de informação com estes serviços seguem diferentes padrões. De entre os muitos padrões utilizados, destaca-se o REST (REpresentational State Transfer). O REST é um estilo arquitectural muito utilizado actualmente. Neste estilo arquitectural as operações e propriedades do protocolo HTTP, sobre o qual o World Wide Web funciona, são aproveitadas para realizar as interacções de clientes com serviços web. Em REST, o elemento basilar são os recursos, que correspondem a pedaços de informação que podem ser referenciados por um identificador. Cada recurso tem uma, ou várias, representações, que podem ter diferentes formatos, e que podem mudar na sequência de operações executadas sobre o mesmo. Um serviço web que adere ao estilo arquitectural REST é chamado de serviço REST. Para programar clientes de um serviço REST é fundamental que esteja disponível uma boa documentação da sua API, com especificações claras das suas operações e dos dados trocados nestas operações entre os clientes e o serviço. No desenvolvimento deste tipo de serviços são utilizadas linguagens de descrição de interfaces, tal como a OpenAPI Specification, o RAML ou a API Blueprint. Estas linguagens permitem especificar formalmente as operações suportadas por um serviço REST e oferecem a capacidade de documentar os dados que são trocados durante as interacções com o serviço. Apesar da sua popularidade, estas linguagens de especificação têm um poder expressivo limitado. Uma das limitações é que não terem capacidade para descrever com precisão o comportamento das diferentes operações. Numa tentativa de endereçar estas limitações, tem vindo a ser desenvolvida a linguagem HeadREST. A linguagem tem um sistema de tipos refinados que permite restringir os valores admissíveis de um tipo, e portanto descrever com mais rigor os tipos dos dados trocados num serviço REST. Para permitir especificar com precisão as operações de um serviço REST, a linguagem HeadREST dispõe de asserções. Estas asserções, semelhantes aos triplos de Hoare, são compostas por uma pré-condição, um URI template da operação e uma pós-condição. As asserções especificam que, quando a pré-condição é satisfeita, a execução da operação estabelece a pós-condição. Devido ao sistema de tipos refinados não é possível resolver através de regras sintácticas as relações de subtipagem. Para endereçar esta situação foi tomada a decisão de utilizar um procedimento semântico para tratar destas situações. A relação de subtipagem é transformada em fórmulas lógicas de primeira ordem, que são depois dadas a um SMT solver para as resolver. Apesar do seu grande poder expressivo, o HeadREST, como linguagem de especificação, está longe de ser perfeita. Um dos problemas mais importantes está relacionado com a sua usabilidade. Apesar da linguagem permitir descrever operações com grande rigor e detalhe, isso é feito à custa de asserções bastante complexas que são não só difíceis de escrever correctamente, como de compreender. Muitas das linguagens de especificação de serviços REST oferecem, mesmo que de forma limitada, uma forma de expressar o que o serviço exige em termos de autenticação e/ou autorização. Existem vários tipos de autenticação e autorização que podem ser usados para restringir acesso a recursos em serviços REST, por exemplo, API keys, Tokens, http authentication&HTTP digest, OAuth 2.0, OpenID Connect. Para além disto, cada serviço REST pode tomar abordagens diferentes em relação a políticas de autorização. Este trabalho endereçou estes dois problemas e pretendeu contribuir com soluções que os ajudassem a resolver. Para o problema de usabilidade, a solução concebida passou pela criação de extensões para a linguagem com ênfase em expressões derivadas. A linguagem foi estendida com: (i) iteradores quantificados que permitem expressar melhor propriedades sobre arrays, (ii) interpolação para permitir criar Strings a partir de URIs de uma forma mais simples e directa, (iii) um operador de extracção que permite aceder à representação de um recurso se esta for única e finalmente, (iv) funções que permitem abstrair expressões repetidas de uma forma mais flexível (apenas as funções não são derivadas). A abordagem para endereçar a especificação de políticas de segurança em APIs REST assentou na adição (i) de um novo tipo Principal, correspondente às entidades autenticadas e (ii) de uma função não-interpretada principalof capturando o Principal autenticado por um valor usado na autenticação. A linguagem foi estendida com a definição de funções não-interpretadas, para permitir que sejam feitas associações entre o tipo Principal e outros dados que possam vir de diferentes fontes (representações, templates de URIs, corpo dos pedidos, etc.), dando assim a possibilidade de especificar os diferentes tipos de políticas de segurança usadas em serviços REST. A avaliação das soluções propostas foi realizada de diferentes formas. Foi realizado um estudo com utilizadores envolvendo a resposta a um questionário com perguntas sobre a linguagem HeadREST antes e depois das extensões e foi feito um estudo quantitativo a comparar o impacto das extensões em termos de métricas de complexidade das especificações e no desempenho do validador. Para avaliar as extensões referentes à segurança foram realizados alguns casos de estudo, envolvendo a especificação parcial de alguns serviços REST do "mundo-real". Foi ainda explorado o impacto que as extensões introduzidas na linguagem têm nas ferramentas que actualmente fazem parte do ecossistema HeadREST: (i) a ferramenta HeadREST-RTester, que permite testar automaticamente a conformidade da implementação de um serviço REST contra uma especificação HeadREST da sua API, (ii) a ferramenta HeadREST-Codegen, que faz a geração de código, e (iii) a linguagem SafeRestScript, uma linguagem de script em que é realizada estaticamente a validação das chamadas a serviços REST cujas APIs tenham sido especificadas com HeadREST. A linguagem HeadREST possui um validador, um plug-in para o IDE Eclipse e uma versão headless para ser utilizada no terminal. |
|---|---|
| Autores principais: | Medeiros, Francisco Robalinho |
| Assunto: | REST Tipos Refinados Linguagens de Descrição de Interfaces REST-Segurança Segurança Teses de mestrado - 2020 |
| Ano: | 2020 |
| País: | Portugal |
| Tipo de documento: | dissertação de mestrado |
| Tipo de acesso: | acesso aberto |
| Instituição associada: | Universidade de Lisboa |
| Idioma: | inglês |
| Origem: | Repositório da Universidade de Lisboa |
| Resumo: | Actualmente, observa-se o crescimento contínuo de serviços web, sem sinais de abrandar. As trocas de informação com estes serviços seguem diferentes padrões. De entre os muitos padrões utilizados, destaca-se o REST (REpresentational State Transfer). O REST é um estilo arquitectural muito utilizado actualmente. Neste estilo arquitectural as operações e propriedades do protocolo HTTP, sobre o qual o World Wide Web funciona, são aproveitadas para realizar as interacções de clientes com serviços web. Em REST, o elemento basilar são os recursos, que correspondem a pedaços de informação que podem ser referenciados por um identificador. Cada recurso tem uma, ou várias, representações, que podem ter diferentes formatos, e que podem mudar na sequência de operações executadas sobre o mesmo. Um serviço web que adere ao estilo arquitectural REST é chamado de serviço REST. Para programar clientes de um serviço REST é fundamental que esteja disponível uma boa documentação da sua API, com especificações claras das suas operações e dos dados trocados nestas operações entre os clientes e o serviço. No desenvolvimento deste tipo de serviços são utilizadas linguagens de descrição de interfaces, tal como a OpenAPI Specification, o RAML ou a API Blueprint. Estas linguagens permitem especificar formalmente as operações suportadas por um serviço REST e oferecem a capacidade de documentar os dados que são trocados durante as interacções com o serviço. Apesar da sua popularidade, estas linguagens de especificação têm um poder expressivo limitado. Uma das limitações é que não terem capacidade para descrever com precisão o comportamento das diferentes operações. Numa tentativa de endereçar estas limitações, tem vindo a ser desenvolvida a linguagem HeadREST. A linguagem tem um sistema de tipos refinados que permite restringir os valores admissíveis de um tipo, e portanto descrever com mais rigor os tipos dos dados trocados num serviço REST. Para permitir especificar com precisão as operações de um serviço REST, a linguagem HeadREST dispõe de asserções. Estas asserções, semelhantes aos triplos de Hoare, são compostas por uma pré-condição, um URI template da operação e uma pós-condição. As asserções especificam que, quando a pré-condição é satisfeita, a execução da operação estabelece a pós-condição. Devido ao sistema de tipos refinados não é possível resolver através de regras sintácticas as relações de subtipagem. Para endereçar esta situação foi tomada a decisão de utilizar um procedimento semântico para tratar destas situações. A relação de subtipagem é transformada em fórmulas lógicas de primeira ordem, que são depois dadas a um SMT solver para as resolver. Apesar do seu grande poder expressivo, o HeadREST, como linguagem de especificação, está longe de ser perfeita. Um dos problemas mais importantes está relacionado com a sua usabilidade. Apesar da linguagem permitir descrever operações com grande rigor e detalhe, isso é feito à custa de asserções bastante complexas que são não só difíceis de escrever correctamente, como de compreender. Muitas das linguagens de especificação de serviços REST oferecem, mesmo que de forma limitada, uma forma de expressar o que o serviço exige em termos de autenticação e/ou autorização. Existem vários tipos de autenticação e autorização que podem ser usados para restringir acesso a recursos em serviços REST, por exemplo, API keys, Tokens, http authentication&HTTP digest, OAuth 2.0, OpenID Connect. Para além disto, cada serviço REST pode tomar abordagens diferentes em relação a políticas de autorização. Este trabalho endereçou estes dois problemas e pretendeu contribuir com soluções que os ajudassem a resolver. Para o problema de usabilidade, a solução concebida passou pela criação de extensões para a linguagem com ênfase em expressões derivadas. A linguagem foi estendida com: (i) iteradores quantificados que permitem expressar melhor propriedades sobre arrays, (ii) interpolação para permitir criar Strings a partir de URIs de uma forma mais simples e directa, (iii) um operador de extracção que permite aceder à representação de um recurso se esta for única e finalmente, (iv) funções que permitem abstrair expressões repetidas de uma forma mais flexível (apenas as funções não são derivadas). A abordagem para endereçar a especificação de políticas de segurança em APIs REST assentou na adição (i) de um novo tipo Principal, correspondente às entidades autenticadas e (ii) de uma função não-interpretada principalof capturando o Principal autenticado por um valor usado na autenticação. A linguagem foi estendida com a definição de funções não-interpretadas, para permitir que sejam feitas associações entre o tipo Principal e outros dados que possam vir de diferentes fontes (representações, templates de URIs, corpo dos pedidos, etc.), dando assim a possibilidade de especificar os diferentes tipos de políticas de segurança usadas em serviços REST. A avaliação das soluções propostas foi realizada de diferentes formas. Foi realizado um estudo com utilizadores envolvendo a resposta a um questionário com perguntas sobre a linguagem HeadREST antes e depois das extensões e foi feito um estudo quantitativo a comparar o impacto das extensões em termos de métricas de complexidade das especificações e no desempenho do validador. Para avaliar as extensões referentes à segurança foram realizados alguns casos de estudo, envolvendo a especificação parcial de alguns serviços REST do "mundo-real". Foi ainda explorado o impacto que as extensões introduzidas na linguagem têm nas ferramentas que actualmente fazem parte do ecossistema HeadREST: (i) a ferramenta HeadREST-RTester, que permite testar automaticamente a conformidade da implementação de um serviço REST contra uma especificação HeadREST da sua API, (ii) a ferramenta HeadREST-Codegen, que faz a geração de código, e (iii) a linguagem SafeRestScript, uma linguagem de script em que é realizada estaticamente a validação das chamadas a serviços REST cujas APIs tenham sido especificadas com HeadREST. A linguagem HeadREST possui um validador, um plug-in para o IDE Eclipse e uma versão headless para ser utilizada no terminal. |
|---|