Escolar Documentos
Profissional Documentos
Cultura Documentos
uma capacidadeé uma referência que não pode ser falsificada a um objeto ou re-
curso junto com um conjunto de permissões para acessar esse recurso. Para ilus-
trar como a segurança baseada em capacidade difere da segurança baseada em
identidade, considere as duas maneiras a seguir para copiar um arquivo em siste-
mas UNIX 1 :
cp a.txt b.txt
cat <a.txt >b.txt
Se você pensar nas permissões que cada um desses comandos precisa, o cp co-
mandoprecisa ser capaz de abrir qualquer arquivo que você possa nomear para
leitura e gravação. Para permitir isso, o UNIX executa o cp comando com as mes-
mas permissões de sua própria conta de usuário, para que possa fazer qualquer
coisa que você fizer, incluindo excluir todos os seus arquivos e enviar suas fotos
privadas por e-mail para um estranho. Isso viola o POLA porque o comando re-
cebe muito mais permissões do que precisa. o cat comando, por outro lado, só
precisa ler de sua entrada e gravar em sua saída. Ele não precisa de nenhuma
permissão (mas é claro que o UNIX dá todas as suas permissões de qualquer ma-
neira). Um descritor de arquivo é um exemplo de capacidade, porque combina
uma referência a algum recurso junto com um conjunto de permissões para atuar
nesse recurso.
O acesso aos recursos é feito por meio de referências infalíveis aos objetos que
também concedem autoridade para acessar esse recurso. Em um sistema base-
ado em identidade, qualquer pessoa pode tentar acessar um recurso, mas pode
ter o acesso negado, dependendo de quem é. Em um sistema baseado em capa-
cidade, é impossível enviar uma solicitação a um recurso se você não tiver ca-
pacidade de acessá-lo. Por exemplo, é impossível gravar em um descritor de ar-
quivo que seu processo não possui. Você verá na seção 9.2 como isso é imple-
mentado para APIs REST.
Os recursos fornecem acesso refinado a recursos individuais e geralmente su-
portam o POLA de forma mais natural do que os sistemas baseados em identi-
dade. É muito mais fácil delegar uma pequena parte de sua autoridade a outra
pessoa, dando-lhe alguns recursos sem dar-lhe acesso a toda a sua conta.
A capacidade de compartilhar recursos facilmente pode dificultar a determina-
ção de quem tem acesso a quais recursos por meio de sua API. Na prática, isso
também é verdade para sistemas baseados em identidade, pois as pessoas com-
partilham o acesso de outras maneiras (como compartilhando senhas).
Alguns sistemas baseados em recursos não oferecem suporte à revogação de re-
cursos depois que eles foram concedidos. Quando a revogação é suportada, a
revogação de um recurso amplamente compartilhado pode negar o acesso a
mais pessoas do que o pretendido.
Uma das razões pelas quais a segurança baseada em capacidade é menos usada
do que a segurança baseada em identidade é devido à crença generalizada de que
as capacidades são difíceis de controlar devido ao fácil compartilhamento e à apa-
rente dificuldade de revogação. Na verdade, esses problemas são resolvidos por
sistemas de capacidade do mundo real, conforme discutido no artigo Capability
Myths Demolished, de Mark S. Miller, Ka-Ping Yee e Jonathan Shapiro (
http://srl.cs.jhu.edu/pubs/ SRL2003-02.pdf). Para dar um exemplo, geralmente é as-
sumido que os recursos podem ser usados apenas para controle de acesso discrici-
onário, porque o criador de um objeto (como um arquivo) pode compartilhar re-
cursos para acessar esse arquivo com qualquer pessoa. Mas em um sistema de ca-
pacidade pura, as comunicações entre as pessoas também são controladas por ca-
pacidades (como é a capacidade de criar arquivos em primeiro lugar); portanto,
se Alice criar um novo arquivo, ela poderá compartilhar a capacidade de acessar
esse arquivo com Bob somente se ela tem uma capacidade que lhe permite se co-
municar com Bob. Claro, nada impede que Bob peça a Alice pessoalmente para
executar ações no arquivo, mas esse é um problema que nenhum sistema de con-
trole de acesso pode evitar.
As APIs Chooser e Saver fornecem várias vantagens sobre um fluxo OAuth2 nor-
mal para este caso de uso simples de compartilhamento de arquivo:
O autor do aplicativo não precisa decidir com antecedência qual recurso pre-
cisa acessar. Em vez disso, eles apenas informam ao Dropbox que precisam de
um arquivo para abrir ou salvar dados, e o Dropbox permite que o usuário de-
cida qual arquivo usar. O aplicativo nunca consegue ver uma lista dos outros
arquivos do usuário.
Como o aplicativo não está solicitando acesso de longo prazo à conta do usuá-
rio, não há necessidade de uma página de consentimento para garantir que o
usuário saiba o acesso concedido. A seleção de um arquivo na IU indica implici-
tamente o consentimento e, como o escopo é tão refinado, os riscos de abuso
são muito menores.
A interface do usuário é implementada pelo Dropbox e, portanto, é consistente
para todos os aplicativos e páginas da Web que usam a API. Pequenos detalhes
como o item de menu “Recente” funcionam de forma consistente em todos os
aplicativos.
Para esses casos de uso, os recursos fornecem uma experiência de usuário muito
intuitiva e natural que também é significativamente mais segura do que as alter-
nativas. Muitas vezes, assume-se que existe uma troca natural entre segurança e
usabilidade: quanto mais seguro for um sistema, mais difícil será usá-lo. Os recur-
sos parecem desafiar essa sabedoria convencional, porque mudar para um geren-
ciamento de permissões mais refinado permite padrões de interação mais conve-
nientes. O usuário escolhe os arquivos com os quais deseja trabalhar e o sistema
concede ao aplicativo acesso apenas a esses arquivos, sem a necessidade de um
complicado processo de consentimento.
Deputados confusos e autoridade ambiental
Arquivoos descritores contam com regiões especiais de memória que podem ser
alteradas apenas por código privilegiado no kernel do sistema operacional para
garantir que os processos não possam adulterar ou criar descritores de arquivo
falsos. Linguagens de programação de capacidade segura também são capazes de
evitar adulterações, controlando o tempo de execução em que o código é execu-
tado. Para uma API REST, isso não é uma opção porque você não pode controlar a
execução de clientes remotos, portanto, outra técnica precisa ser usada para ga-
rantir que os recursos não possam ser falsificados ou adulterados. Você já viu vá-
rias técnicas para criar tokens que não podem ser falsificados nos capítulos 4, 5 e
6, usando strings aleatórias grandes que não podem ser adivinhadas ou usando
técnicas criptográficas para autenticar os tokens. Você pode reutilizar esses for-
matos de token para criar tokens de capacidade, mas há várias diferenças
importantes:
Para criar um URI de capacidade, você pode combinar um URI normal com um to-
ken de segurança. Existem várias maneiras de fazer isso, conforme mostrado na
figura 9.2.
https://dl.dropboxusercontent.com/1/view/8ygmwuqzf1l6x7c/
➥ livro/gráficos/CH08_FIG8.2_RBAC.png
https://dl.dropboxusercontent.com/1/view/
➥ livro/gráficos/CH08_FIG8.2_RBAC.png?token=8ygmwuqzf1l6x7c
Há um formulário padrão para esses URIs quando o token é um token OAuth2 de-
finido pela RFC 6750 ( https://tools.ietf.org/html/rfc6750#section-2.3 ) usando o
nome do parâmetro access_token . Geralmente, essa é a abordagem mais sim-
ples de implementar porque não requer alterações nos recursos existentes, mas
compartilha algumas deficiências de segurança com a abordagem baseada em
caminho:
Para proteger os URIs de capacidade contra essas ameaças, você pode codificar o
token no componente de fragmento ou no URI ou até mesmo na parte userinfo
que foi originalmente projetada para armazenar credenciais HTTP Basic em um
URI. Nem o fragmento nem o componente userinfo de um URI são enviados para
um servidor da Web por padrão e ambos são removidos dos URIs comunicados
nos Referer cabeçalhos.
Credenciais em URIs: uma lição da história
1. Quais dos seguintes são bons lugares para codificar um token em um URI de
capacidade?
1. o fragmento
2. O nome do host
3. O nome do esquema
4. O número da porta
5. O componente do caminho
6. Os parâmetros de consulta
7. O componente de informações do usuário
2. Quais das opções a seguir são diferenças entre recursos e autenticação baseada
em token?
1. Os recursos são mais volumosos do que os tokens de autenticação.
2. Os recursos não podem ser revogados, mas os tokens de autenticação podem.
3. Os recursos estão vinculados a um único recurso, enquanto os tokens de au-
tenticação são aplicáveis a todos os recursos em uma API.
4. Os tokens de autenticação estão vinculados a uma identidade de usuário in-
dividual, enquanto os tokens de capacidade podem ser compartilhados entre
os usuários
5. Os tokens de autenticação são de curta duração, enquanto os recursos geral-
mente têm uma vida útil mais longa.
importar com.manning.apisecurityinaction.token.SecureTokenStore;
importar com.manning.apisecurityinaction.token.TokenStore.Token;
importar faísca.*;
importar java.net.*;
importar java.time.*;
importar java.util.*;
importar java.time.Instant.now estático;
classe pública CapabilityController {
private final SecureTokenStore tokenStore; ❶
Você também deve passar o novo controlador como um argumento adicional para
o SpaceController construtor, porque em breve você o usará para criar URIs de
capacidade:
var database = Database.forDataSource(datasource);
var capController = new CapabilityController(
new DatabaseTokenStore(banco de dados));
var spaceController = new SpaceController(banco de dados, capController);
var userController = new UserController(banco de dados);
Vocêagora pode ajustar a API para retornar URIs de capacidade que podem ser
usados para acessar mensagens e espaços sociais. Onde a API atualmente retorna
um caminho simples para um espaço social ou mensagem como /spaces/1 ,
você retornará um URI de capacidade total que pode ser usado para acessá-lo.
Para fazer isso, você precisa adicionar o CapabilityController como um novo
argumento para o SpaceController construtor, conforme mostrado na Lista-
gem 9.2. Abra SpaceController.java em seu editor e inclua o novo campo e o argu-
mento do construtor.
database.updateUnique(
"INSERT INTO espaços(space_id, nome, proprietário)" +
"VALUES(?, ?, ?);", spaceId, spaceName, proprietário);
resposta.status(201);
response.header("Localização", uri.toASCIIString()); ❸
VALIDANDO CAPACIDADES
Para concluir a troca de recursos, você precisa alterar os filtros usados para pes-
quisar as permissões do usuário atual para usar o novo filtro de recursos. Abra
Main.java em seu editor e localize os três before () filtros que chamam atual-
mente userController::lookupPermissions e alterá-los para chamar o filtro
do controlador de capacidade. Eu destaquei a mudança de controlador em
negrito:
before("/espaços/:espaçoId/mensagens",
capController::lookupPermissions);
before("/espaços/:espaçoId/mensagens/*",
capController::lookupPermissions);
before("/espaços/:espaçoId/membros",
capController::lookupPermissions);
Agora você pode reiniciar o servidor API, criar um usuário e criar um novo es-
paço social. Isso funciona exatamente como antes, mas agora você recebe de volta
um URI de capacidade em resposta à criaçãoaespaço:
DICA Você pode estar se perguntando por que teve que criar um usuário e au-
tenticar antes de poder criar um espaço no último exemplo. Afinal, não acabamos
de abandonar a segurança baseada em identidade? A resposta é que a identidade
não está sendo usada para autorizar a ação neste caso, porque nenhuma permis-
são é necessária para criar um novo espaço social. Em vez disso, a autenticação é
necessária apenas para responsabilidade, para que haja um registro no log de au-
ditoria de quem criou o espaço.
9.2.3 ÓDIOAS
Se você é um aficionado por design RESTful, deve saber que fazer com que o cli-
ente apenas saiba que precisa adicionar /messages ao final de um URI para
acessar as mensagens é uma violação de um princípio REST central, que é que as
interações do cliente devem ser conduzidas por hipertexto (links). Em vez de um
cliente precisar ter conhecimento específico sobre como acessar recursos em sua
API, o servidor deve informar ao cliente onde estão os recursos e como acessá-los.
Esse princípio recebe o nome rápido de Hypertext as the Engine of Application
State, ou HATEOAS para abreviar. Roy Fielding, criador dos princípios de design
REST, declarou que esse é um aspecto crucial do design da API REST (
http://mng.bz/Jx6v ).
Você pode permitir que um cliente acesse e publique novas mensagens no espaço
social retornando um segundo URI do createSpace operação que permite o
acesso ao recurso de mensagens para este espaço, conforme a Listagem 9.5. Você
simplesmente cria um segundo URI de capacidade para esse caminho e o retorna
como outro link na resposta JSON. Abra SpaceController.java em seu editor nova-
mente e atualize o final do método createSpace para criar o segundo link. As no-
vas linhas de código são destacadas em negrito.
resposta.status(201);
response.header("Localização", uri.toASCIIString());
Se você reiniciar o servidor de API novamente e criar um novo espaço, verá que
os dois URIs agora são retornados. Uma solicitação GET para o messages URI re-
tornará uma lista de mensagens no espaço, que agora pode ser acessada por qual-
quer pessoa com esse URI de capacidade. Por exemplo, você pode abrir esse link
diretamente em um navegador da web. Você também pode POSTAR uma nova
mensagem no mesmo URI. Novamente, esta operação requer autenticação além
do URI de capacidade porque a mensagem alega explicitamente ser de um usuá-
rio específico e, portanto, a API deve autenticar essa declaração. A permissão para
postar a mensagem vem da capacidade, enquanto a prova de identidade vem da
autenticação:
Os URIs de capacidade retornados até agora fornecem acesso total aos recursos
que eles identificam, conforme indicado pelas rwd permissões (ler-escrever-ex-
cluir, se você se lembra do capítulo 3). Isso significa que é impossível dar a outra
pessoa acesso ao espaço sem dar a ela acesso total para excluir as mensagens de
outro usuário. Tanto para POLA!
Uma solução para isso é retornar vários URIs de capacidade com diferentes níveis
de acesso, conforme mostrado na Listagem 9.6. O proprietário do espaço pode for-
necer os URIs mais restritos, mantendo o URI que concede privilégios totais ape-
nas para moderadores confiáveis. Abra SpaceController.java novamente e inclua
os recursos adicionais da listagem. Reinicie a API e tente executar ações diferen-
tes com recursos diferentes.
resposta.status(201);
response.header("Localização", uri.toASCIIString());
questionário
3. Os URIs de capacidade para cada espaço usam tokens de banco de dados que
nunca expiram. Com o tempo, isso preencherá o banco de dados com tokens.
Quais das opções a seguir são maneiras de evitar isso?
1. Tokens de hash no banco de dados
2. Usando um formato de token independente, como JWTs
3. Usando um banco de dados nativo da nuvem que pode ser dimensionado
para conter todos os tokens
4. Usando o HmacTokenStore além do DatabaseTokenStore
5. Reutilizar um token existente quando o mesmo recurso já foi emitido
4. Qual é a principal razão pela qual o HATEOAS é um importante princípio de de-
sign ao usar URIs de capacidade? Escolha uma resposta.
1. HATEOAS é uma parte central do REST.
2. URIs de capacidade são difíceis de lembrar.
3. Os clientes não são confiáveis para criar seus próprios URIs.
4. Roy Fielding, o inventor do REST, diz que é importante.
5. Um cliente não pode criar seus próprios URIs de capacidade e, portanto, só
pode acessar outros recursos por meio de links.
DentroNa seção 9.2.1, mencionei que colocar o token no caminho do URI ou nos
parâmetros de consulta é menos do que ideal porque eles podem vazar nos logs
de auditoria, Referer cabeçalhos e no histórico do navegador. Esses riscos são li-
mitados quando os URIs de capacidade são usados em uma API, mas podem ser
um problema real quando esses URIs são expostos diretamente aos usuários em
um cliente de navegador da web. Se você usar URIs de capacidade em sua API, os
clientes baseados em navegador precisarão traduzir de alguma forma os URIs
usados na API em URIs usados para navegar na IU. Uma abordagem natural seria
usar URIs de capacidade para isso também, reutilizando os tokens dos URIs da
API. Nesta seção, você verá como fazer isso com segurança.
Uma abordagem para esse problema é colocar o token em uma parte do URI que
normalmente não é enviada ao servidor ou incluída nos Referer cabeçalhos. A
solução original foi desenvolvida para o servidor Waterken que usava URIs de ca-
pacidade extensivamente, sob o nome web-keys(
http://waterken.sourceforge.net/web-key/ ). Em uma chave da web, o token que
não pode ser adivinhado é armazenado no componente de fragmento do URI; ou
seja, o bit após um caractere # no final do URI. O fragmento é normalmente usado
para saltar para um local específico dentro de um documento maior e tem a van-
tagem de nunca ser enviado ao servidor por clientes e nunca incluído em um Re-
ferer cabeçalho ou window.referrer campoem JavaScript e, portanto, é menos
suscetível a vazamentos. A desvantagem é que, como o servidor não vê o token, o
cliente deve extraí-lo do URI e enviá-lo ao servidor por outros meios.
No Waterken, que foi projetado para aplicativos da web, quando um usuário cli-
cava em um link de chave da web no navegador, ele carregava um modelo sim-
ples de página JavaScript. O JavaScript então extraiu o token do fragmento de con-
sulta (usando a window.location.hash variável) e fez uma segunda chamada
para o servidor web, passando o token em um parâmetro de consulta. O fluxo é
mostrado na figura 9.3.
Figura 9.3 No design de chave da Web Waterken para URIs de capacidade, o token
é armazenado no fragmento do URI, que nunca é enviado ao servidor. Quando
um navegador carrega esse URI, ele carrega inicialmente uma página JavaScript
estática que extrai o token do fragmento e o usa para fazer solicitações Ajax à API.
O modelo JavaScript pode ser armazenado em cache pelo navegador, evitando a
ida e volta extra para solicitações subsequentes.
return busca(capUrl.href) ❹
.then(resposta => resposta.json())
.then(retorno de chamada)
.catch(err => console.error('Erro: ', err));
}
❷ Apague o fragmento.
Tudoas chamadas para a API Natter agora são autorizadas apenas usando tokens
de capacidade, que têm como escopo um recurso individual e não estão vincula-
dos a nenhum usuário. Como você viu com o exemplo do navegador de mensa-
gens simples na última seção, você pode até mesmo codificar URIs de capacidade
somente leitura em uma página da Web para permitir a navegação completa-
mente anônima de mensagens. Algumas chamadas de API ainda exigem autenti-
cação do usuário, como criar um novo espaço ou postar uma mensagem. O mo-
tivo é que essas ações da API envolvem declarações sobre quem é o usuário, por-
tanto, você ainda precisa autenticar essas declarações para garantir que sejam ge-
nuínas, por motivos de responsabilidade e não por autorização. Caso contrário,
qualquer pessoa com um URI de capacidade para postar mensagens em um es-
paço poderia usá-lo para representar qualquer outro usuário.
questionário
Vocêpode se perguntar se você pode acabar com o token anti-CSRF agora que está
usando recursos para controle de acesso, que são imunes ao CSRF. Isso seria um
erro, porque um invasor com capacidade genuína de acessar a API ainda pode
usar um ataque CSRF para fazer com que suas solicitações pareçam vir de um
usuário diferente. A autoridade para acessar a API vem do URI de capacidade do
invasor, mas a identidade do usuário vem do cookie. Se você mantiver o token
anti-CSRF existente, os clientes deverão enviar três credenciais a cada solicitação:
Se um token de capacidade for roubado, ele não poderá ser usado sem um coo-
kie de login válido para o usuário. Se o cookie for definido com os sinalizadores
HttpOnly e Secure, será muito mais difícil roubá-lo.
Agora você pode remover o token anti-CSRF separado porque cada URI de capa-
cidade atua efetivamente como um token anti-CSRF. O cookie não pode ser
usado sem o recurso e o recurso não pode ser usado sem o cookie.
Agora você pode excluir o código que verifica o token anti-CSRF no CookieTo-
kenStore se desejar e contar com o código de capacidade para proteção contra
CSRF. Consulte o capítulo 4 para ver como era a versão original antes da proteção
CSRF ser adicionada. Você também precisará ajustar o
TokenController.validateToken métodopara não rejeitar uma solicitação
que não tenha um token anti-CSRF. Se você ficar preso, confira o capítulo 09 no fi-
nal do repositório GitHub que acompanha o livro, que possui todas as alterações
necessárias.
COMPARTILHAMENTO DE ACESSO
Agora você pode adicionar uma nova rota à Main classepara expor esta nova ope-
ração. Abra o arquivo Main.java e adicione a seguinte linha ao main método:
post("/capabilities", capController::share);
Agora você pode chamar esse ponto de extremidade para trocar um URI de capa-
cidade privilegiada, como o URI de mensagens-rwd retornado da criação de um
espaço, como no exemplo a seguir:
O novo URI de capacidade na resposta só pode ser usado pelo usuário demo2 e
fornece apenas permissão de leitura no espaço. Você pode usar esse recurso para
criar compartilhamento de recursos para suas APIs. Por exemplo, se um usuário
compartilhar diretamente um URI de capacidade próprio com outro usuário, em
vez de negar o acesso completamente, você pode permitir que ele solicite acesso.
Isso é o que acontece no Google Docs se você seguir um link para um documento
ao qual não tem acesso. O proprietário do documento pode então aprovar o
acesso. No Google Docs, isso é feito adicionando uma entrada a uma lista de con-
trole de acesso (capítulo 3) associada a cada documento, mas com recursos, o pro-
prietário pode gerar um URI de recurso que é enviado por e-mailparaadestinatá-
rio.
Os macaroons fornecem uma solução para esse problema, permitindo que qual-
quer pessoa acrescente advertências a um recurso que restringe como ele pode
ser usado. Os macarons foram inventados por uma equipe de pesquisadores aca-
dêmicos e do Google em um artigo publicado em 2014 ( https://ai.google/
research/pubs/pub41892 ).
método = GET
desde >= 2019-10-12T12:00:00Z
❸ Calcule uma nova tag para cada advertência usando a tag antiga como chave.
<dependência>
<groupId>com.github.nitram509</groupId>
<artifactId>jmacaroons</artifactId>
<version>0.4.1</version>
</dependência>
pacote com.manning.apisecurityinaction.token;
importar java.security.Key;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Opcional;
import com.github.nitram509.jmacaroons.*;
import com.github.nitram509.jmacaroons.verifier.*;
import spark.Request;
@Sobrepor
public String create(Solicitação de solicitação, Token token) {
var identificador = delegado.create(solicitação, token); ❶
var macaroon = MacaroonsBuilder.create("", ❷
macKey.getEncoded(), identificador); ❷
return macaroon.serialize(); ❸
}
}
Esses métodos de fábrica são mostrados na listagem 9.14 e são muito semelhantes
aos que você criou no capítulo 5, então abra o arquivo MacaroonTokenStore.java
novamente e adicione esses novos métodos.
@Sobrepor
public void revoke(Solicitação de solicitação, String tokenId) {
var macaroon = MacaroonsBuilder.deserialize(tokenId);
delegado.revoke(pedido, macaroon.identificador); ❸
}
Se agora você usar a API para criar um novo espaço, verá os tokens de biscoito
sendo usados nos URIs de capacidade retornados da chamada de API. Você pode
copiar e colar esses tokens no depurador em http://macaroons.io para ver as par-
tes componentes.
oas advertências mais simples são advertências próprias, que podem ser verifica-
das pela API puramente com base na solicitação da API e no ambiente atual. Essas
advertências são representadas como strings e não há um formato padrão. A
única advertência de primeira parte comumente implementada é definir um
tempo de expiração para o biscoito usando a sintaxe:
Você pode pensar nessa ressalva como sendo a reivindicação de expiração (exp)
em um JWT (capítulo 6). Os tokens emitidos pela API Natter já possuem um tempo
de expiração, mas um cliente pode querer criar uma cópia de seu token com um
tempo de expiração mais restrito, conforme discutido na seção 9.3.1 sobre adver-
tências contextuais.
@Sobrepor
public Opcional<Token> read(Request request, String tokenId) {
var macaroon = MacaroonsBuilder.deserialize(tokenId);
var verificador = new MacaroonsVerifier(macaroon);
verifier.satisfyGeneral(new TimestampCaveatVerifier()); ❶
if (verifier.isValid(macKey.getEncoded())) {
return delegado.read(pedido, macaroon.identificador);
}
return Opcional.vazio();
}
@Sobrepor
public boolean VerifyCaveat(String advertência) {
if (caveat.startsWith("since > ")) { ❶
var minSince = Instant.parse(caveat.substring(8)); ❶
verifier.satisfyGeneral(new SinceVerifier(request));
Para adicionar uma advertência a um biscoito, você pode analisá-lo usando a Ma-
caroonsBuilder classee depois use o add_first_party_caveat métodoacres-
centar ressalvas, conforme a listagem 9.18. A listagem é um programa de linha de
comando autônomo para adicionar ressalvas a um biscoito. Ele primeiro analisa o
macaroon, que é passado como o primeiro argumento para o programa e, em se-
guida, percorre todos os argumentos restantes, tratando-os como advertências.
Por fim, ele imprime o macaroon resultante como uma string novamente. Nave-
gue até a pasta src/main/java/com/manning/apisecurityinaction e crie um novo
arquivo chamado CaveatAppender.java e digite o conteúdo da listagem.
pacote com.manning.apisecurityinaction;
import com.github.nitram509.jmacaroons.MacaroonsBuilder;
import static com.github.nitram509.jmacaroons.MacaroonsBuilder.deserialize;
Para testar o programa, use a API Natter para criar um novo espaço social e rece-
ber um URI de capacidade com um token de biscoito. Neste exemplo, eu usei
o jq e cut utilitários para extrair o token do macaroon, mas você pode copiar e
colar manualmente se preferir:
NEWMAC=$(mvn -q exec:java \
-Dexec.mainClass= com.manning.apisecurityinaction.CaveatAppender \
-Dexec.args="$MAC 'time < 2020-08-03T12:05:00Z'")
Você pode usar este novo macaroon para ler todas as mensagens no espaço até
que expire:
curl -u demo:changeit -i \
"https://localhost:4567/spaces/1/messages?access_token=$NEWMAC"
Depois que o novo limite de tempo expirar, a solicitação retornará um erro 403
Forbidden, mas o token original ainda funcionará (basta alterar $NEWMAC para
$MAC na consulta para testar isso). Isso demonstra a principal vantagem dos ma-
caroons: depois de configurar o servidor, é muito fácil (e rápido) para um cliente
acrescentar advertências contextuais que restringem o uso de um token, prote-
gendo esses tokens em caso de comprometimento. Um cliente JavaScript execu-
tado em um navegador da Web pode usar uma biblioteca de macaroon JavaScript
para anexar advertências sempre que usar um token com apenas algumas linhas
decódigo.
9.3.4 Advertências de terceiros
Por exemplo, um cliente pode receber um token de macaroon de longo prazo para
realizar atividades bancárias em nome de um usuário, como iniciar pagamentos
de sua conta. Além das advertências de terceiros que restringem quanto o cliente
pode transferir em uma única transação, o banco pode anexar uma advertência
de terceiros que exige que o cliente obtenha autorização para cada pagamento de
um serviço de autorização de transação. O serviço de autorização de transação ve-
rifica os detalhes da transação e potencialmente confirma a transação direta-
mente com o usuário antes de emitir um macaroon de descarga vinculado a essa
transação. Esse padrão de ter um único token de longa duração fornecendo acesso
geral, mas exigindo macaroons de descarga de curta duração para autorizar tran-
sações específicas é um caso de uso perfeito para ressalvas de terceiros.
Diferenteuma advertência de primeira parte, que é uma string simples, uma ad-
vertência de terceiros tem três componentes:
macaroon = MacaroonsBuilder.modify(macaroon) ❶
.add_third_party_caveat("https://auth.example.com", ❷
segredo, caveatId) ❷
.getMacaroon();
O segredo indecifrável deve ser gerado com alta entropia, como um valor de 256
bits de um SecureRandom :
questionário
6. Qual das opções a seguir se aplica a uma advertência de primeira parte? Seleci-
one tudo que se aplica.
1. É uma corda simples.
2. É satisfeito com um macaroon de descarga.
3. Requer que o cliente entre em contato com outro serviço.
4. Pode ser verificado no ponto de uso pela API.
5. Ele tem um identificador, uma string secreta e uma dica de localização.
7. Qual das opções a seguir se aplica a uma advertência de terceiros? Selecione
tudo que se aplica.
1. É uma corda simples.
2. É satisfeito com um macaroon de descarga.
3. Requer que o cliente entre em contato com outro serviço.
4. Pode ser verificado no ponto de uso pela API.
5. Ele tem um identificador, uma string secreta e uma dica de localização.
1. uma,e, f ou g são lugares aceitáveis para codificar o token. Os outros podem in-
terferir no funcionamento do URI.
2. c, d e e.
3. b e e impediriam que os tokens preenchessem o banco de dados. Usar um
banco de dados mais escalável provavelmente apenas atrasará isso (e aumen-
tará seus custos).
4. e. Sem retornar links, um cliente não tem como criar URIs para outros recursos.
5. d. Se o servidor redirecionar, o navegador copiará o fragmento para o novo
URL, a menos que um novo seja especificado. Isso pode vazar o token para ou-
tros servidores. Por exemplo, se você redirecionar o usuário para um serviço de
login externo, o componente de fragmento não é enviado ao servidor e não é
incluído nos cabeçalhos do Referer.
6. a e d.
7. b,c,ee.
Resumo
Os URIs de capacidade podem ser usados para fornecer acesso refinado a re-
cursos individuais por meio de sua API. Um URI de capacidade combina um
identificador para um recurso junto com um conjunto de permissões para aces-
sar esse recurso.
Como alternativa ao controle de acesso baseado em identidade, os recursos evi-
tam a autoridade ambiente que pode levar a ataques confusos de representan-
tes e adotar o POLA.
Há muitas maneiras de formar URIs de capacidade com diferentes compensa-
ções. As formas mais simples codificam um token aleatório no caminho do URI
ou nos parâmetros de consulta. Variantes mais seguras codificam o token no
fragmento ou nos componentes de informações do usuário, mas têm um custo
de maior complexidade para os clientes.
Vincular um URI de capacidade a uma sessão de usuário aumenta a segurança
de ambos, porque reduz o risco de roubo de tokens de capacidade e pode ser
usado para evitar ataques CSRF. Isso torna mais difícil compartilhar URIs de
capacidade.
Os macaroons permitem que qualquer pessoa restrinja uma capacidade ane-
xando advertências que podem ser verificadas criptograficamente e aplicadas
por uma API. Advertências contextuais podem ser anexadas logo antes de um
biscoito ser usado para proteger um token contra uso indevido.
As advertências primárias codificam condições simples que podem ser verifica-
das localmente por uma API, como restringir a hora do dia em que um token
pode ser usado. As advertências de terceiros exigem que o cliente obtenha um
macaroon de descarga de um serviço externo que comprove que ele atende a
uma condição, de modo que o usuário seja funcionário de uma determinada
empresa ou tenha terminado18 anos de idade.
1.
Este exemplo foi retirado de “Paradigm Regained: Abstraction Mechanisms for Ac-
cess Control”. Veja http://mng.bz/Mog7 .
2.
Existem propostas para fazer o OAuth funcionar melhor para esses tipos de opera-
ções transacionais pontuais, como https://oauth.xyz, mas elas ainda exigem que o
aplicativo saiba qual recurso deseja acessar antes de iniciar o fluxo.
3.
Você pode obter o projeto em https://github.com/NeilMadden/apisecurityinaction
se não tiver trabalhado no capítulo 8. Confira o capítulo 09 da ramificação.
4.
Neste capítulo, você retornará links como URIs dentro de campos JSON normais.
Existem formas padrão de representar links em JSON, como JSON-LD (
https://json-ld.org ), mas não vou abordá-las neste livro.
5.
Se você é um entusiasta da programação funcional, isso pode ser escrito elegante-
mente como uma operação de dobra à esquerda ou redução.
6.
Meu empregador, ForgeRock, adicionou suporte experimental para macaroons ao
seu software de servidor de autorização.