Professional Documents
Culture Documents
7 OAuth2 and OpenID Connect - API Security in Action
7 OAuth2 and OpenID Connect - API Security in Action
SAIBA MAIS SOBRE ISSO VejaOAuth2 in Action por Justin Richer e Antonio
Sanso (Manning, 2017; https://www.manning.com/books/oauth-2-in-action ) se
você quiser aprender como um AS funciona em detalhes.
Como todos os mecanismos descritos neste capítulo são padrões, os padrões funci-
onarão com qualquer AS compatível com os padrões com poucas alterações. Con-
sulte o apêndice A para obter detalhes sobre como instalar e configurar um AS
para uso neste capítulo.
A solução para esses problemas é restringir as operações da API que podem ser
realizadas com um token, permitindo que ele seja utilizado apenas dentro de um
escopo bem definido. Por exemplo, você pode permitir que seu software de conta-
bilidade leia transações que ocorreram nos últimos 30 dias, mas não permitir que
visualize ou crie novos pagamentos na conta. O escopo do acesso que você conce-
deu ao software de contabilidade é, portanto, limitado ao acesso somente leitura a
transações recentes. Normalmente, o escopo de um token é representado como
um ou mais rótulos de string armazenados como um atributo do token. Por exem-
plo, você pode usar o rótulo de escopo transactions:read para permitir acesso
de leitura a transações e payment :create permitir a configuração de um novo
pagamento de uma conta. Como pode haver mais de um rótulo de escopo associ-
ado a um token, eles geralmente são chamados de escopos. Os escopos (rótulos) de
um token definem coletivamente o escopo de acesso que ele concede. A Figura 7.1
mostra alguns dos rótulos de escopo disponíveis ao criar um token de acesso pes-
soal no GitHub.
Figura 7.1 O GitHub permite que os usuários criem manualmente tokens com es-
copo, que eles chamam de tokens de acesso pessoal. Os tokens nunca expiram,
mas podem ser restritos para permitir acesso apenas a partes da API do GitHub
definindo o escopo do token.
DEFINIÇÃO Um token com escopo limita as operações que podem ser executa-
das com esse token. O conjunto de operações permitidas é conhecido como escopo
do token. O escopo de um token é especificado por um ou mais rótulos de escopo,
que geralmente são referidos coletivamente como escopos.
Adaptandoo endpoint de login existente para emitir tokens com escopo é muito
simples, conforme mostrado na Listagem 7.1. Quando uma solicitação de login é
recebida, se ela contiver um parâmetro de escopo, você poderá associar esse es-
copo ao token armazenando-o nos atributos do token. Você pode definir um con-
junto padrão de escopos a serem concedidos se o parâmetro de escopo não for es-
pecificado. Abra o arquivo TokenController.java em seu editor e atualize o mé-
todo de login para incluir suporte para tokens com escopo, como na listagem 7.1.
Na parte superior do arquivo, adicione uma nova constante listando todos os es-
copos. No Natter, você usará escopos correspondentes a cada operação da API:
resposta.status(201);
retornar novo JSONObject()
.put("token", tokenId);
}
❸ Se o escopo do token não contiver o escopo necessário, retorne uma resposta 403
Forbidden.
Agora você pode usar esse método para impor qual escopo é necessário para exe-
cutar determinadas operações, conforme mostrado na Listagem 7.3. Decidir quais
escopos devem ser usados por sua API e exatamente qual escopo deve ser neces-
sário para quais operações é um tópico complexo, discutido com mais detalhes na
próxima seção. Para este exemplo, você pode usar escopos refinados correspon-
dentes a cada operação de API: create_space , post_message e assim por di-
ante. Para evitar a escalação de privilégios, você deve exigir um escopo específico
para chamar o endpoint de login, porque isso pode ser usado para obter um token
com qualquer escopo, ignorando efetivamente as verificações de escopo. 2 Por ou-
tro lado, revogar um token chamando o endpoint de logout não deve exigir ne-
nhum escopo. Abra o arquivo Main.java em seu editor e adicione verificações de
escopo usando o tokenController.requireScope métodocomo mostrado
emListagem 7.3.
before("/sessions", userController::requireAuthentication);
before("/sessions", ❶
tokenController.requireScope("POST", "full_access")); ❶
post("/sessions", tokenController::login);
delete("/sessions", tokenController::logout); ❷
before("/spaces", userController::requireAuthentication);
before("/spaces", ❸
tokenController.requireScope("POST", "create_space")); ❸
post("/spaces", spaceController::createSpace);
before("/spaces/*/messages", ❸
tokenController.requireScope("POST", "post_message")); ❸
before("/espaços/:espaçoId/mensagens",
userController.requirePermission("POST", "w"));
post("/spaces/:spaceId/messages", spaceController::postMessage);
before("/spaces/*/messages/*", ❸
tokenController.requireScope("GET", "read_message")); ❸
before("/espaços/:espaçoId/mensagens/*",
userController.requirePermission("GET", "r"));
get("/espaços/:espaçoId/messages/:msgId",
spaceController::readMessage);
before("/spaces/*/messages", ❸
tokenController.requireScope("GET", "list_messages")); ❸
before("/espaços/:espaçoId/mensagens",
userController.requirePermission("GET", "r"));
get("/spaces/:spaceId/messages", spaceController::findMessages);
before("/spaces/*/members", ❸
tokenController.requireScope("POST", "add_member")); ❸
before("/espaços/:espaçoId/membros",
userController.requirePermission("POST", "rwd"));
post("/spaces/:spaceId/members", spaceController::addMember);
before("/spaces/*/messages/*", ❸
tokenController.requireScope("DELETE", "delete_message")); ❸
before("/espaços/:espaçoId/mensagens/*",
userController.requirePermission("DELETE", "d"));
delete("/espaços/:spaceId/messages/:msgId",
moderadorController::deletePost);
NoÀ primeira vista, pode parecer que os escopos e as permissões são muito seme-
lhantes, mas há uma distinção no que eles são usados, conforme mostrado na fi-
gura 7.2. Normalmente, uma API pertence e é operada por uma autoridade cen-
tral, como uma empresa ou organização. Quem pode acessar a API e o que eles
podem fazer é controlado inteiramente pela autoridade central. Este é um exem-
plo de controle de acesso obrigatório, porque os usuários não têm controle sobre
suas próprias permissões ou as de outros usuários. Por outro lado, quando um
usuário delega parte de seu acesso a um aplicativo ou serviço de terceiros, isso é
conhecido como controle de acesso discricionário, porque cabe ao usuário quanto
de seu acesso conceder ao terceiro. Os escopos OAuth tratam fundamentalmente
do controle de acesso discricionário, enquanto as permissões tradicionais (que
você implementou usando ACLs no capítulo 3) podem ser usadas para controle de
acesso obrigatório.
Figura 7.2 As permissões geralmente são concedidas por uma autoridade central
que possui a API que está sendo acessada. Um usuário não pode escolher ou alte-
rar suas próprias permissões. Os escopos permitem que um usuário delegue parte
de sua autoridade a um aplicativo de terceiros, restringindo quanto acesso eles
concedem usando escopos.
Enquanto os escopos são usados para delegação, as permissões podem ser usadas
para acesso obrigatório ou discricionário. As permissões de arquivo no UNIX e na
maioria dos outros sistemas operacionais populares podem ser definidas pelo
proprietário do arquivo para conceder acesso a outros usuários e, assim, imple-
mentar o DAC. Por outro lado, alguns sistemas operacionais usados por militares e
governos têm controles de acesso obrigatórios que impedem que alguém com au-
torização apenas SECRET leia documentos ULTRA SECRETOS, por exemplo, inde-
pendentemente de o proprietário do arquivo querer conceder-lhes acesso. 3 Os
métodos para organizar e impor permissões para MAC são abordados no capítulo
8. Os escopos OAuth fornecem uma maneira de colocar DAC em camadas sobre
uma camada de segurança MAC existente.
Colocando a distinção teórica entre MAC e DAC de lado, a distinção mais prática
entre escopos e permissões está relacionada a como eles são projetados. O admi-
nistrador de uma API projeta permissões para refletir as metas de segurança do
sistema. Essas permissões refletem as políticas organizacionais. Por exemplo, um
funcionário que executa um trabalho pode ter acesso de leitura e gravação a to-
dos os documentos em uma unidade compartilhada. As permissões devem ser
projetadas com base nas decisões de controle de acesso que um administrador
pode querer tomar para usuários individuais, enquanto os escopos devem ser
projetados com base na previsão de como os usuários podem querer delegar seu
acesso a aplicativos e serviços de terceiros.
Um exemplo dessa distinção pode ser visto no design dos escopos OAuth usados
pelo Google para acessar seusServiços do Google Cloud Platform. Serviços que li-
dam com tarefas de administração do sistema, como oO serviço de gerenciamento
de chaves para lidar com chaves criptográficas possui apenas um único escopo
que concede acesso a toda essa API. O acesso a chaves individuais é gerenciado
por meio de permissões. Mas as APIs que fornecem acesso aos dados individuais
do usuário, como a API Fitness ( http://mng.bz/EEDJ ) são divididas em escopos
muito mais refinados, permitindo que os usuários escolham exatamente com
quais estatísticas de saúde desejam compartilhar terceiros, conforme figura 7.3.
Fornecer aos usuários um controle refinado ao compartilhar seus dados é uma
parte fundamental de uma estratégia moderna de privacidade e consentimento e
pode ser exigido em alguns casos por legislação como o Regulamento Geral de
Proteção de Dados da UE(RGPD).
Ao escolher quais escopos expor em sua API, você deve considerar qual nível de
controle seus usuários provavelmente precisarão ao delegar acesso. Não há uma
resposta simples para essa pergunta, e o design do escopo geralmente requer vá-
rias iterações de colaboração entre arquitetos de segurança, designers de experi-
ência do usuário edo utilizadorrepresentantes.
Figura 7.3 Os escopos OAuth do Google Cloud Platform são muito refinados para
APIs do sistema, como acesso ao banco de dados ou gerenciamento de chaves.
Para APIs que processam dados do usuário, como a API Fitness, muitos outros es-
copos são definidos, permitindo aos usuários maior controle sobre o que compar-
tilham com aplicativos e serviços de terceiros.
questionário
1. Quais das opções a seguir são diferenças típicas entre escopos e permissões?
1. Os escopos são mais refinados do que as permissões.
2. Os escopos são mais refinados do que as permissões.
3. Os escopos usam nomes mais longos do que permissões.
4. As permissões geralmente são definidas por uma autoridade central, en-
quanto os escopos são projetados para delegar o acesso.
5. Os escopos normalmente restringem apenas as operações de API que podem
ser chamadas. As permissões também restringem quais objetos podem ser
acessados.
Emborapermitir que seus usuários criem manualmente tokens com escopo para
aplicativos de terceiros é uma melhoria em relação ao compartilhamento de to-
kens sem escopo ou credenciais de usuário, pode ser confuso e propenso a erros.
Um usuário pode não saber quais escopos são necessários para que o aplicativo
funcione e, portanto, pode criar um token com poucos escopos ou talvez delegar
todos os escopos apenas para que o aplicativo funcione.
OAuth usa termos específicos para se referir às quatro entidades mostradas na fi-
gura 7.4, com base no papel que desempenham na interação:
Antes daum cliente pode solicitar um token de acesso, ele deve primeiro se regis-
trar no AS e obter um ID de cliente exclusivo. Isso pode ser feito manualmente
por um administrador do sistema ou existe um padrão para permitir que os clien-
tes se registrem dinamicamente em um AS ( https://tools.ietf .org/html/rfc7591 ).
SAIBA MAIS OAuth2 in Action de Justin Richer e Antonio Sanso (Manning, 2017;
https://www.manning.com/books/oauth-2-in-action ) abrange o registro dinâmico
de clientes com mais detalhes.
A principal diferença entre os dois é que um cliente confidencial pode ter suas
próprias credenciais de clienteque ele usa para autenticar no servidor de autori-
zação. Isso garante que um invasor não possa se passar por um cliente legítimo
para tentar obter um token de acesso de um usuário em um ataque de phishing.
Um aplicativo móvel ou baseado em navegador não pode manter as credenciais
em segredo porque qualquer usuário que fizer o download do aplicativo pode ex-
traí-las. 4 Para clientes públicos, são utilizadas medidas alternativas de proteção
contra esses ataques, como você verá em breve.
Figura 7.4 Para acessar uma API usando OAuth2, um aplicativo deve primeiro ob-
ter um token de acesso do Authorization Server (AS). O aplicativo informa ao AS
qual escopo de acesso ele requer. O AS verifica se o usuário consente com esse
acesso e emite um token de acesso ao aplicativo. O aplicativo pode usar o token de
acesso para acessar a API em nome do usuário.
CUIDADO O ROPC pode ser útil para testes, mas deve ser evitado na maioria dos
casos. Pode ser obsoleto em versões futuras do padrão.
NoConcessão de Código de Autorização, o cliente primeiro usa um navegador
da Web para navegar até um terminal de autorização dedicadono AS, indi-
cando quais escopos ele requer. O AS então autentica o usuário diretamente no
navegador e pede consentimento para o acesso do cliente. Se o usuário concor-
dar, o AS gera um código de autorização e o entrega ao cliente para trocá-lo por
um token de acesso no endpoint do token. A concessão do código de autoriza-
ção é abordada com mais detalhes na próxima seção.
oConcessão de credenciais do clientepermite que o cliente obtenha um token de
acesso usando suas próprias credenciais, sem nenhum usuário envolvido. Essa
concessão pode ser útil em alguns padrões de comunicação de microsserviços
discutidos no capítulo 11.
Existem vários tipos de subsídios adicionais para situações mais específicas,
como oconcessão de autorização de dispositivo(também conhecido como fluxo
de dispositivo) para dispositivos sem qualquer meio direto de interação do
usuário. Não há registro de tipos de concessão definidos, mas sites como
https://oauth.net/2/grant-types/ listam os tipos mais usados. A concessão de au-
torização do dispositivo é abordada no capítulo 13. As concessões OAuth2 são
extensíveis, portanto, novos tipos de concessão podem ser adicionados quando
uma das concessões existentes não se encaixa.
E a concessão implícita?
$ curl -d 'grant_type=password&client_id=test ❶
➥ &scope=read_messages+post_message ❶
➥ &username=demo&password=changeit' ❷
➥ https://as.example.com:8443/oauth2/access_token
{
"access_token":"I4d9xuSQABWthy71it8UaRNM2JA", ❸
"scope":"post_message read_messages",
"token_type":"Portador",
"expires_in":3599}
❶ Especifique o tipo de concessão, ID do cliente e escopo solicitado como campos de
formulário POST.
❸ O token de acesso é retornado em uma resposta JSON, junto com seus metadados.
oOs padrões OAuth2 não definem caminhos específicos para o token e os end-
points de autorização, portanto, eles podem variar de AS para AS. Como as exten-
sões foram adicionadas ao OAuth, vários outros endpoints foram adicionados,
juntamente com várias configurações para novos recursos. Para evitar que cada
cliente tenha que codificar os locais desses terminais, há uma maneira padrão de
descobrir essas configurações usando um documento de descoberta de serviço
publicado em um local conhecido. Originalmente desenvolvido para o perfil Ope-
nID Connect do OAuth (que será abordado posteriormente neste capítulo), ele foi
adotado pelo OAuth2 ( https://tools.ietf.org/html/rfc8414 ).
{
"authorization_endpoint":
"http://openam.example.com:8080/oauth2/authorize",
"token_endpoint":
"http://openam.example.com:8080/oauth2/access_token",
...
}
AVISO Como o cliente enviará credenciais e tokens de acesso para muitos desses
endpoints, é fundamental que eles sejam descobertos por uma fonte confiável. Re-
cupere o documento de descoberta apenas por HTTPS de um URL confiável.
questionário
O cliente pode então trocar o código de autorização por um token de acesso cha-
mando o endpoint do token no AS. Ele envia o código de autorização no corpo de
uma requisição POST, utilizando a application/x-www-form-urlencoded co-
dificação utilizada para formulários HTML, com os seguintes parâmetros:
Indique o tipo de concessão do código de autorização que está sendo usado, in-
cluindo grant_ type=authorization_code .
Inclua o ID do cliente no client_id parâmetroou forneça credenciais de cli-
ente para identificar o cliente.
Inclua o URI de redirecionamento usado na solicitação original no redirect
_uri parâmetro.
Por fim, inclua o código de autorização como valor do code parâmetro.
Esta é uma chamada HTTPS direta do cliente para o AS, em vez de um redirecio-
namento no navegador da Web e, portanto, o token de acesso retornado ao cliente
é protegido contra roubo ou adulteração. Um exemplo de solicitação para o end-
point do token se parece com o seguinte:
POST /token HTTP/1.1
Host: as.example.com
Tipo de conteúdo: application/x-www-form-urlencoded
Autorização: Basic dGVzdDpwYXNzd29yZA== ❶
grant_type=authorization_code& ❷
code=kdYfMS7H3sOO5y_sKhpdV6NFfik& ❷
redirect_uri=https://client.example.net/callback ❸
HTTP/1.1 200 OK
Tipo de conteúdo: aplicativo/json
{
"access_token":"QdT8POxT2SReqKNtcRDicEgIgkk", ❶
"scope":"post_message read_messages", ❷
"token_type":"Portador",
"expires_in":3599} ❸
❶ O token de acesso
Assim que o cliente obtiver um token de acesso, ele poderá usá-lo para acessar as
APIs no servidor de recursos, incluindo-o em um Authorization: Bearer ca-
beçalho, exatamente como você fez nos capítulos anteriores. Você verá como vali-
dar um token de acesso em sua API na seção 7.4.
Uma desvantagem dos esquemas de URI de uso privado é que qualquer aplicativo
pode se registrar para lidar com qualquer esquema de URI, portanto, um aplica-
tivo mal-intencionado pode registrar o mesmo esquema que seu cliente legítimo.
Se um usuário tiver o aplicativo mal-intencionado instalado, o redirecionamento
do AS com um código de autorização pode fazer com que o aplicativo mal-intenci-
onado seja ativado em vez de seu aplicativo legítimo. URIs de redirecionamento
HTTPS registrados no Android (App Links) e iOS (Universal Links) evitam esse
problema porque um aplicativo só pode reivindicar parte do espaço de endereço
de um site se o site em questão publicar um documento JSON explicitamente con-
cedendo permissão a esse aplicativo. Por exemplo, para permitir que seu aplica-
tivo iOS manipule solicitações para https://example.com/app/callback, você deve
publicar o seguinte arquivo JSON em https://example.com/.well-known/apple-app-
site -Associação:
{
"aplicativos": {
"aplicativos": [],
"detalhes": [
{ "appID": "9JA89QQLNQ.com.example.myapp", ❶
"paths": ["/app/callback"] }] ❷
}
}
request.session(true).attribute("verificador", verificador); ❷
$ curl -d 'grant_type=password
➥ &scope=read_messages+post_message
➥ &username=demo&password=changeit'
➥ -u test:password
➥ https://as.example.com:8443/oauth2/access_token
{
"access_token":"B9KbdZYwajmgVxr65SzL-z2Dt-4",
"refresh_token":"sBac5bgCLCjWmtjQ8Weji2mCrbI", ❶
"scope":"post_message read_messages",
"token_type":"Bearer","expires_in":3599}
❶ Um token de atualização
Quando o token de acesso expira, o cliente pode usar o token de atualização para
obter um novo token de acesso do AS sem que o proprietário do recurso precise
aprovar a solicitação novamente. Como o token de atualização é enviado apenas
por um canal seguro entre o cliente e o AS, ele é considerado mais seguro do que
um token de acesso que pode ser enviado para várias APIs diferentes.
Muitas vezes, o AS pode ser configurado para emitir um novo token de atualiza-
ção ao mesmo tempo (revogando o antigo), garantindo que cada token de atuali-
zação seja usado apenas uma vez. Isso pode ser usado para detectar roubo de to-
ken de atualização: quando o invasor usa o token de atualização, ele para de fun-
cionar para olegítimocliente.
questionário
4. Qual tipo de URI deve ser preferido como URI de redirecionamento para um cli-
ente móvel?
1. Um URI HTTPS reivindicado
2. Um esquema de URI de uso privado, como myapp:/ /cb
5. Verdadeiro ou falso: A concessão do código de autorização sempre deve ser
usada em combinação com PKCE.
Agoraque você aprendeu como obter um token de acesso para um cliente, precisa
aprender como validar o token em sua API. Nos capítulos anteriores, era simples
procurar um token no banco de dados de tokens local. Para OAuth2, isso não é
mais tão simples quando os tokens são emitidos pelo AS e não pela API. Embora
você possa compartilhar um banco de dados de token entre o AS e cada API, isso
não é desejável porque compartilhar o acesso ao banco de dados aumenta o risco
de comprometimento. Um invasor pode tentar acessar o banco de dados por meio
de qualquer um dos sistemas conectados, aumentando a superfície de ataque. Se
apenas uma API conectada ao banco de dados tiver uma vulnerabilidade de inje-
ção de SQL, isso comprometeria a segurança de todos.
Originalmente, o OAuth2 não fornecia uma solução para esse problema e deixava
para o AS e os servidores de recursos decidir como coordenar a validação dos to-
kens. Isso mudou com a publicação do padrão OAuth2 Token Introspection (
https://tools.ietf .org/html/rfc7662 ) em 2015, que descreve um endpoint HTTP pa-
drão no AS que o RS pode chamar para validar um token de acesso e recuperar
detalhes sobre seu escopo e proprietário do recurso. Outra solução popular é usar
JWTs como formato para tokens de acesso, permitindo que o RS valide localmente
o token e extraia os detalhes necessários das declarações JSON incorporadas. Você
aprenderá como usar ambos os mecanismos nesta seção.
pacote com.manning.apisecurityinaction.token;
import org.json.JSONObject;
import spark.Request;
importar java.io.IOException;
importar java.net.*;
importar java.net.http.*;
importar java.net.http.HttpRequest.BodyPublishers;
importar java.net.http.HttpResponse.BodyHandlers;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
importar java.util.*;
importar estático java.nio.charset.StandardCharsets.UTF_8;
public class OAuth2TokenStore implementa SecureTokenStore {
this.httpClient = HttpClient.newHttpClient();
}
@Sobrepor
public String create(Solicitação de solicitação, Token token) {
lançar novo UnsupportedOperationException(); ❸
}
@Sobrepor
public void revoke(Solicitação de solicitação, String tokenId) {
lançar novo UnsupportedOperationException(); ❸
}
}
❶ Injete o URI do endpoint de introspecção de token.
Para validar um token, você precisa fazer uma solicitação POST para o endpoint
de introspecção que passa o token. Você pode usar a biblioteca cliente HTTP em
java.net.http, que foi adicionada no Java 11 (para versões anteriores, você pode
usar Apache HttpComponents, https://hc.apache.org/httpcomponents-client-ga/).
Como o token não é confiável antes da chamada, primeiro você deve validá-lo
para garantir que esteja em conformidade com a sintaxe permitida para tokens
de acesso. Como você aprendeu no capítulo 2, é importante sempre validar todas
as entradas, e isso é especialmente importante quando a entrada for incluída em
uma chamada para outro sistema. O padrão não especifica um tamanho máximo
para tokens de acesso, mas você deve impor um limite de cerca de 1 KB ou menos,
o que deve ser suficiente para a maioria dos formatos de token (se o token de
acesso for um JWT, ele pode ficar muito grande e você pode necessidade de au-
mentar esse limite). O token deve ser codificado em URL para incluir no corpo do
POST como o token parâmetro. É importante codificar adequadamente os parâ-
metros ao chamar outro sistema para impedir que um invasor manipule o con-
teúdo da solicitação (consulte a seção 2.6 do capítulo 2). Você também pode incluir
um token_ type_hint parâmetropara indicar que é um token de acesso, mas
isso é opcional.
DICA Para evitar fazer uma chamada HTTP toda vez que um cliente usa um to-
ken de acesso com sua API, você pode armazenar em cache a resposta por um
curto período de tempo, indexada pelo token. Quanto mais você armazenar em
cache a resposta, mais tempo levará para sua API descobrir que um token foi re-
vogado, portanto, você deve equilibrar o desempenho com a segurança com base
em seu modelo de ameaça.
@Sobrepor
public Opcional<Token> read(Request request, String tokenId) {
if (!tokenId.matches("[\\x20-\\x7E]{1,1024}")) { ❶
return Opcional.vazio();
}
tentar {
var httpResponse = httpClient.send(httpRequest,
BodyHandlers.ofString());
if (httpResponse.statusCode() == 200) {
var json = new JSONObject(httpResponse.body());
if (json.getBoolean("active")) { ❹
return processResponse(json); ❹
}
}
} catch (IOException e) {
lança nova RuntimeException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
lança nova RuntimeException(e);
}
return Opcional.vazio();
}
Vários campos opcionais são permitidos na resposta JSON, incluindo todas as de-
clarações JWT válidas (consulte o capítulo 6). Os campos mais importantes estão
listados na tabela 7.1. Como todos esses campos são opcionais, você deve estar
preparado para a falta deles. Este é um aspecto infeliz da especificação, porque
muitas vezes não há alternativa senão rejeitar um token se seu escopo ou proprie-
tário do recurso não puder ser estabelecido. Felizmente, a maioria dos softwares
AS gera valores sensatos para esses campos.
Campo Descrição
A Listagem 7.7 mostra como processar os campos JSON restantes extraindo o pro-
prietário do recurso do sub campo, o tempo de expiração do exp campo e o es-
copo do scope campo. Você também pode extrair outros campos de interesse,
como o client_id , que podem ser informações úteis para adicionar aos logs de
auditoria. Abra OAuth2TokenStore.java novamente e adicione o processRes-
ponse métododa listagem.
token.attributes.put("scope", response.getString("scope")); ❶
token.attributes.put("client_id", ❶
response.optString("client_id")); ❶
return Opcional.of(token);
}
Embora você tenha usado o sub campo para extrair um ID para o usuário, isso
nem sempre pode ser apropriado. O assunto autenticado de um token precisa cor-
responder às entradas nas tabelas users e permissions no banco de dados que
definem as listas de controle de acesso para os espaços sociais do Natter. Se não
corresponderem, as solicitações de um cliente serão negadas, mesmo que tenham
um token de acesso válido. Você deve verificar a documentação do seu AS para
ver qual campo usar para corresponder aos seus IDs de usuário existentes.
Agora você pode alternar a API Natter para usar tokens de acesso OAuth2 alte-
rando o TokenStore em Main.java para usar o OAuth2TokenStore , passando o
URI do endpoint de introspecção de token do seu AS e o ID do cliente e o segredo
que você registrou para a API do Natter (consulte o apêndice A para obter
instruções):
var introspectionEndpoint =
URI.create("https://as.example.com:8443/oauth2/introspect");
SecureTokenStore tokenStore = new OAuth2TokenStore( ❶
introspectionEndpoint, clientId, clientSecret); ❶
var tokenController = new TokenController(tokenStore);
Assim que o AS e a API estiverem na mesma página sobre nomes de usuário, você
pode obter um token de acesso do AS e usá-lo para acessar a API do Natter, como
no exemplo a seguir usando a concessão ROPC:
$ curl -u test:password \ ❶
-d 'grant_type=password&scope=create_space+post_message ❶
➥ &username=demo&password=changeit' \ ❶
https://openam.example.com:8443/openam/oauth2/access_token
{"access_token":"_Avja0SO-6vAz-caub31eh5RLDU",
"scope":"post_message create_space",
"token_type":"Bearer","expires_in":3599}
$ curl -H 'Tipo de conteúdo: aplicativo/json' \
-H 'Autorização: Portador _Avja0SO-6vAz-caub31eh5RLDU' \ ❷
-d '{"name":"test","owner":"demo"}' https://localhost:4567/spaces
{"nome":"teste","uri":"/espaços/1"}
Tentar executar uma ação que não é permitida pelo escopo do token de acesso re-
sultará em um erro 403 Proibido devido aos filtros de controle de acesso que você
adicionou no início destecapítulo:
❶ O pedido é proibido.
cadeias de certificados
Ao configurar o armazenamento confiável para seu cliente HTTPS, você pode op-
tar por confiar diretamente no certificado do servidor para esse servidor. Embora
isso pareça mais seguro, significa que sempre que o servidor alterar seu certifi-
cado, o cliente precisará ser atualizado para confiar no novo. Muitos certificados
de servidor são válidos por apenas 90 dias. Se o servidor for comprometido, o cli-
ente continuará confiando no certificado comprometido até que seja atualizado
manualmente para removê-lo do armazenamento confiável.
Para evitar esses problemas, o certificado do servidor é assinado por uma CA, que
possui um certificado (autoassinado). Quando um cliente se conecta ao servidor,
ele recebe o certificado atual do servidor durante o handshake. Para verificar se
esse certificado é genuíno, ele procura o certificado de CA correspondente no ar-
mazenamento confiável do cliente e verifica se o certificado do servidor foi assi-
nado por essa CA e se não expirou ou foi revogado.
importar javax.net.ssl.*;
importar java.security.*;
importar java.net.http.*;
var sslParams = new SSLParameters();
sslParams.setProtocols( ❶
new String[] { "TLSv1.3", "TLSv1.2" }); ❶
sslParams.setCipherSuites(new String[] {
"TLS_AES_128_GCM_SHA256", ❷
"TLS_AES_256_GCM_SHA384", ❷
"TLS_CHACHA20_POLY1305_SHA256", ❷
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ❸
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ❸
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", ❸ "TLS_ECDHE_RSA_WITH_AES_2
", ❸ "
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", ❸
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" ❸
});
sslParams.setUseCipherSuitesOrder(true);
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
tentar {
var trustCerts = KeyStore.getInstance("PKCS12"); ❹
TrustedCerts.load( ❹
new FileInputStream("as.example.com.ca.p12"), ❹
"changeit".toCharArray()); ❹
var tmf = TrustManagerFactory.getInstance("PKIX"); ❹
tmf.init(trustedCerts); ❹
var sslContext = SSLContext.getInstance("TLS"); ❹
sslContext.init(null, tmf.getTrustManagers(), null); ❹
this.httpClient = HttpClient.newBuilder()
.sslParameters(sslParams) ❺
.sslContext(sslContext) ❺
.construir();
} catch (GeneralSecurityException | IOException e) {
lança nova RuntimeException(e);
}
❹ O SSLContext deve ser configurado para confiar apenas na CA usada pelo seu AS.
pacote com.manning.apisecurityinaction;
importar java.net.*;
importar java.net.http.*;
importar java.net.http.HttpResponse.BodyHandlers;
importar java.util.Base64;
if (args.length != 3) {
lançar novo IllegalArgumentException(
"Token RevokeAccessToken clientId clientSecret");
}
httpClient.send(httpRequest, BodyHandlers.discarding());
}
}
questionário
Para validar um token de acesso baseado em JWT, a API precisa primeiro autenti-
car o JWT usando uma chave criptográfica. No capítulo 6, você usou HMAC simé-
trico ou algoritmos de criptografia autenticados nos quais a mesma chave é usada
para criar e verificar mensagens. Isso significa que qualquer parte que pode veri-
ficar um JWT também pode criar um que será confiável para todas as outras par-
tes. Embora isso seja adequado quando a API e o AS existem dentro do mesmo li-
mite de confiança, torna-se um risco de segurança quando as APIs estão em dife-
rentes limites de confiança. Por exemplo, se o AS estiver em um datacenter dife-
rente da API, a chave agora deve ser compartilhada entre esses dois datacenters.
Se houver muitas APIs que precisam de acesso à chave compartilhada,
Para evitar esses problemas, o AS pode mudar para criptografia de chave pública
usando assinaturas digitais, conforme mostrado na figura 7.8. Em vez de ter uma
única chave compartilhada, o AS tem um par de chaves: uma chave privada e
uma chave pública. O AS pode assinar um JWT usando a chave privada e qual-
quer pessoa com a chave pública pode verificar se a assinatura é genuína. No en-
tanto, a chave pública não pode ser usada para criar uma nova assinatura e, por-
tanto, é seguro compartilhar a chave pública com qualquer API que precise vali-
dar tokens de acesso. Por esse motivo, a criptografia de chave pública também é
conhecida como criptografia assimétrica, pois o detentor de uma chave privada
pode realizar operações diferentes do detentor de uma chave pública. Dado que
apenas o AS precisa criar novos tokens de acesso, o uso de criptografia de chave
pública para JWTs impõe o princípio da menor autoridade (POLA; consulte o capí-
tulo 2), pois garante que as APIs possam apenas verificar tokens de acesso e não
criar novos.
Figura 7.8 Ao usar tokens de acesso baseados em JWT, o AS assina o JWT usando
uma chave privada conhecida apenas pelo AS. A API pode recuperar uma chave
pública correspondente do AS para verificar se o JWT é genuíno. A chave pública
não pode ser usada para criar um novo JWT, garantindo que os tokens de acesso
possam ser emitidos apenas pelo AS.
DICA Embora a criptografia de chave pública seja mais segura nesse sentido,
também é mais complicada com mais maneiras de falhar. As assinaturas digitais
também são muito mais lentas do que o HMAC e outros algoritmos simétricos - ge-
ralmente 10 a 100 vezes mais lentas para segurança equivalente.
RECUPERANDO A CHAVE PÚBLICA
oA API pode ser configurada diretamente com a chave pública do AS. Por exem-
plo, você pode criar um keystore que contenha a chave pública, que a API pode
ler quando for inicializada. Embora isso funcione, tem algumas desvantagens:
Um keystore Java pode conter apenas certificados, não chaves públicas brutas,
portanto, o AS precisaria criar um certificado autoassinado apenas para permi-
tir que a chave pública fosse importada para o keystore. Isso adiciona comple-
xidade que não seria necessária de outra forma.
Se o AS alterar sua chave pública, o que é recomendado, o keystore precisará
ser atualizado manualmente para listar a nova chave pública e remover a an-
tiga. Como alguns tokens de acesso que usam a chave antiga ainda podem estar
em uso, o keystore pode ter que listar ambas as chaves públicas até que esses
tokens antigos expirem. Isso significa que duas atualizações manuais precisam
ser realizadas: uma para adicionar a nova chave pública e uma segunda atuali-
zação para remover a chave pública antiga quando ela não for mais necessária.
Embora você possa usar cadeias de certificados X.509 para estabelecer confiança
em uma chave por meio de uma autoridade de certificação, assim como para
HTTPS na seção 7.4.2, isso exigiria que a cadeia de certificados fosse anexada a
cada token de acesso JWT (usando o cabeçalho x5c padrãodescrito no capítulo 6).
Isso aumentaria o tamanho do token de acesso além dos limites razoáveis - uma
cadeia de certificados pode ter vários kilobytes de tamanho. Em vez disso, uma so-
lução comum é o AS publicar sua chave pública em um documento JSON conhe-
cido como JWK Set ( https://tools.ietf.org/html/rfc7517 ). Um exemplo de JWK Set é
mostrado na listagem 7.10 e consiste em um objeto JSON com um único keys atri-
buto, cujo valor é uma matriz de JSON Web Keys (consulte o capítulo 6). A API
pode buscar periodicamente o Conjunto JWK de um URI HTTPS fornecido pelo AS.
A API pode confiar nas chaves públicas no Conjunto JWK porque elas foram recu-
peradas por HTTPS de um URI confiável e essa conexão HTTPS foi autenticada
usando o certificado do servidor apresentado durante o handshake TLS.
{"teclas": [ ❶
{
"kty": "CE", ❷
"criança": "I4x/IijvdDsUZMghwNq2gC/7pYQ=",
"usar": "assinar",
"x": "k5wSvW_6JhOuCj-9PdDWdEA4oH90RSmC2GTliiUHAhXj6rmTdE2S-
➥ _zGmMFxufuV",
"y": "XfbR-tRoVcZMCoUrkKtuZUIyfCgAy8b0FWnPZqevwpdoTzGQBOXSN
➥ i6uItN_o4tH",
"crv": "P-384",
"alg": "ES384"
},
{
"kty": "RSA", ❸
"criança": "wU3ifIIaLOUAReRB/FG6eM1P1QM=",
"usar": "assinar",
"n": "10iGQ5l5IdqBP1l5wb5BDBZpSyLs4y_Um-kGv_se0BkRkwMZavGD_Nqjq8x3-
➥ fKNI45nU7E7COAh8gjn6LCXfug57EQfi0gOgKhOhVcLmKqIEXPmqeagvMndsXWIy6k8WP
➥ PwBzSkN5PDLKBXKG_X1BwVvOE9276nrx6lJq3CgNbmiEihovNt_6g5pCxiSarIk2uaG3T
➥ 3Ve6hUJrM0W35QmqrNM9rL3laPgXtCuz4sJJN3rGnQq_25YbUawW9L1MTVbqKxWiyN5Wb
➥ XoWUg8to1DhoQnXzDymIMhFa45NTLhxtdH9CDprXWXWBaWzo8mIFes5yI4AJW4ZSg1PPO
➥ 2UJSQ",
"e": "AQAB",
"alg": "RS256"
}
]}
❶ O JWK Set tem um atributo “keys”, que é um array de JSON Web Keys.
@Sobrepor
public String create(Solicitação de solicitação, Token token) {
lançar novo UnsupportedOperationException();
}
@Sobrepor
public void revoke(Solicitação de solicitação, String tokenId) {
lançar novo UnsupportedOperationException();
}
@Sobrepor
public Opcional<Token> read(Request request, String tokenId) {
// Ver listagem 7.12
}
}
@Sobrepor
public Opcional<Token> read(Request request, String tokenId) {
tentar {
var verificador = new DefaultJWTProcessor<>();
var keySelector = new JWSVerificationKeySelector<>(
signatureAlgorithm, jwkSource);
verificador.setJWSKeySelector(keySelector);
if (!issuer.equals(claims.getIssuer())) { ❷
return Optional.empty(); ❷
}
if (!claims.getAudience().contains(audience)) { ❷
return Optional.empty(); ❷
}
Escopo da string; ❹
try { ❹
scope = Claims.getStringClaim("scope"); ❹
} catch (ParseException e) { ❹
scope = String.join(" ", ❹
Claims.getStringListClaim("scope")); ❹
} ❹
token.attributes.put("escopo", escopo); ❹
return Opcional.of(token);
oO padrão JWS que o JWT usa para assinaturas suporta muitos algoritmos dife-
rentes de assinatura de chave pública, resumidos na tabela 7.2. Como os algorit-
mos de assinatura de chave pública são caros e geralmente limitados na quanti-
dade de dados que podem ser assinados, o conteúdo do JWT é primeiro hash
usando uma função de hash criptográfica e, em seguida, o valor de hash é assi-
nado. O JWS fornece variantes para diferentes funções de hash ao usar o mesmo
algoritmo de assinatura subjacente. Todas as funções de hash permitidas forne-
cem segurança adequada, mas o SHA-512 é o mais seguro e pode ser um pouco
mais rápido do que as outras opções em sistemas de 64 bits. A exceção a esta re-
gra é ao usar assinaturas ECDSA, porque JWS especifica curvas elípticas para usar
junto com cada função de hash; a curva usada com SHA-512 tem uma penalidade
de desempenho significativa em comparação com a curva usada para SHA-256.
Tabela 7.2 Algoritmos de assinatura JWS
RS384 SHA-384
RS512 SHA-512
PS384 SHA-384
PS512 SHA-512
ECDH-
ES+A256KW
AVISO A maioria dos algoritmos JWE são seguros, exceto RSA1_5 os que usam o
antigo algoritmo de preenchimento PKCS#1 versão 1.5. Existem ataques conheci-
dos contra esse algoritmo, então você não deve usá-lo. Este modo de preenchi-
mento foi substituído pelo preenchimento de criptografia assimétrica ideal(OAEP)
que foi padronizado na versão 2 do PKCS#1. O OAEP usa uma função de hash in-
ternamente, então há duas variantes incluídas no JWE: uma usando SHA-1 e outra
usando SHA-256. Como o SHA-1 não é mais considerado seguro, você deve prefe-
rir a variante SHA-256, embora não haja ataques conhecidos contra ele quando
usado com OAEP. No entanto, mesmo o OAEP tem algumas desvantagens porque é
um algoritmo complicado e menos amplamente implementado. A criptografia
RSA também produz texto cifrado maior do que outros modos e a operação de
descriptografia é muito lenta, o que é um problema para um token de acesso que
pode precisar ser descriptografado várias vezes.
Esse padrão permite que o formato dos tokens de acesso mude com o tempo por-
que apenas o AS valida os tokens. Em termos de engenharia de software, a esco-
lha do formato do token é encapsulada pelo AS e oculta dos servidores de recur-
sos, enquanto com JWTs assinados por chave pública, cada API sabe como validar
os tokens, tornando muito mais difícil alterar a representação posteriormente. Pa-
drões mais sofisticados para gerenciar tokens de acesso para ambientes de mi-
crosserviço são abordadosdentroparte 4.
questionário
AVISO Embora possa ser tentador reutilizar um único token de acesso para for-
necer acesso a várias APIs diferentes dentro de uma organização, isso aumenta o
risco se um token for roubado. Prefira usar tokens de acesso separados para cada
API diferente.
Embora o OIDC seja uma extensão do OAuth, ele reorganiza um pouco as partes
porque a API que o cliente deseja acessar (o endpoint UserInfo) faz parte do pró-
prio AS (figura 7.11). Em um fluxo OAuth2 normal, o cliente primeiro falaria com
o AS para obter um token de acesso e depois falaria com a API em um servidor de
recursos separado.
Figura 7.11 No OpenID Connect, o cliente acessa as APIs no próprio AS, portanto,
há apenas duas entidades envolvidas em comparação com as três no OAuth nor-
mal. O cliente é conhecido como parte confiável (RP), enquanto o AS e a API com-
binados são conhecidos como OpenID Provider (OP).
Isso representa muita sobrecarga antes mesmo de você saber o nome do usuário,
portanto, o OIDC fornece uma maneira de retornar algumas das reivindicações de
identidade e autenticação sobre um usuário como um novo tipo de token conhe-
cido como token de ID, que é assinado e opcionalmente criptografado JWT. Esse
token pode ser retornado diretamente do endpoint do token na etapa 2 ou até
mesmo diretamente do endpoint de autorização na etapa 1, em uma variante do
fluxo implícito. Há também um fluxo híbrido no qual o endpoint de autorização
retorna um token de ID diretamente junto com um código de autorização que o
cliente pode então trocar por um token de acesso.
Para validar um token de ID, o cliente deve primeiro processar o token como um
JWT, descriptografando-o se necessário e verificando a assinatura. Quando um cli-
ente se registra em um provedor OIDC, ele especifica a assinatura do token de ID e
os algoritmos de criptografia que deseja usar e pode fornecer chaves públicas a
serem usadas para criptografia, portanto, o cliente deve garantir que o token de
ID recebido use esses algoritmos. O cliente deve, então, verificar as declarações
JWT padrão no token de ID, como os valores de expiração, emissor e público, con-
forme descrito no capítulo 6. O OIDC define várias declarações adicionais que
também devem ser verificadas, descritas na tabela 7.4.
Tabela 7.4 Reivindicações padrão de token de ID
A defesa mais simples contra esses ataques é usar o fluxo de código de autoriza-
ção com PKCE conforme recomendado para todos os fluxos OAuth2. Nesse caso, o
token de ID é emitido apenas pelo OP a partir do endpoint do token em resposta a
uma solicitação HTTPS direta do cliente. Se você decidir usar um fluxo híbrido
para receber um token de ID diretamente no redirecionamento do endpoint de
autorização, o OIDC inclui várias proteções que podem ser empregadas para pro-
teger o fluxo:
O cliente pode incluir um aleatório nonce parâmetro na solicitação e verifique
se o mesmo nonce está incluído no token de ID recebido em resposta. Isso evita
ataques de repetição, pois o nonce em um token de ID repetido não correspon-
derá ao novo valor enviado na nova solicitação. O nonce deve ser gerado alea-
toriamente e armazenado no cliente, assim como o state parâmetro OAuthe o
PKCE code_challenge . (Observe que o parâmetro nonce não está relacio-
nado a um nonce usado na criptografia conforme abordado no capítulo 6.)
O cliente pode solicitar que o token de ID seja criptografado usando uma chave
pública fornecida durante o registro ou usando criptografia AES com uma
chave derivada do segredo do cliente. Isso evita que informações pessoais con-
fidenciais sejam expostas se o token de ID for interceptado. A criptografia sozi-
nha não impede ataques de repetição, portanto, um nonce OIDC ainda deve ser
usado neste caso.
O token de ID pode incluir c_hash e at_hash declarações que contêm hashes
criptográficos do código de autorização e token de acesso associados a uma soli-
citação. O cliente pode compará-los com o código de autorização real e o token
de acesso que recebe para garantir que correspondam. Juntamente com o
nonce e a assinatura criptográfica, isso evita efetivamente que um invasor tro-
que o código de autorização ou o token de acesso na URL de redirecionamento
ao usar os fluxos híbridos ou implícitos.
DICA Você pode usar o mesmo valor aleatório para os parâmetros OAuth sta-
te e OIDC nonce para evitar ter que gerar e armazenar ambos no cliente.
As proteções adicionais fornecidas pelo OIDC podem atenuar muitos dos proble-
mas com a concessão implícita. Mas eles têm um custo de maior complexidade em
comparação com a concessão do código de autorização com PKCE, porque o cli-
ente deve executar várias operações criptográficas complexas e verificar muitos
detalhes do token de ID durante a validação. Com o fluxo de código de autentica-
ção e PKCE, as verificações são realizadas pelo OP quando o código é trocado por
acesso e IDtokens.
Portanto, você não deve usar tokens de ID para conceder acesso a uma API.
NOTE Nunca use tokens de ID para controle de acesso para clientes de terceiros.
Use tokens de acesso para acesso e tokens de ID para identidade. Os tokens de ID
são como nomes de usuários; tokens de acesso são como senhas.
Embora você não deva usar um token de ID para permitir o acesso a uma API,
pode ser necessário procurar informações de identidade sobre um usuário du-
rante o processamento de uma solicitação de API ou precisar impor requisitos de
autenticação específicos. Por exemplo, uma API para iniciar transações financei-
ras pode exigir a garantia de que o usuário foi autenticado recentemente usando
um mecanismo de autenticação forte. Embora essas informações possam ser re-
tornadas de uma solicitação de introspecção de token, isso nem sempre é supor-
tado por todos os softwares de servidor de autorização. Os tokens de ID OIDC for-
necem um formato de token padrão para verificar esses requisitos. Nesse caso,
convém permitir que o cliente passe um token de ID assinado obtido de um OP
confiável. Quando isso é permitido,
Quando a API precisa acessar declarações no token de ID, ela deve primeiro veri-
ficar se é de um OP confiável, validando a assinatura e as declarações do emissor.
Ele também deve garantir que o assunto do token de ID corresponda exatamente
ao proprietário do recurso do token de acesso ou que haja algum outro relaciona-
mento de confiança entre eles. Idealmente, a API deve garantir que seu próprio
identificador esteja no público do token de ID e que o identificador do cliente seja
a parte autorizada ( azp reivindicação), mas nem todos os softwares OP supor-
tam a configuração desses valores corretamente neste caso. A Listagem 7.13 mos-
tra um exemplo de validação das declarações em um token de ID em comparação
com aquelas em um token de acesso que já foi usado para autenticar a solicitação.
Consulte o SignedJwtAccessToken store para obter detalhes sobre como confi-
gurar o verificador JWT.
if (!expectedIssuer.equals(claims.getIssuer())) { ❷
throw new IllegalArgumentException( ❷
"id inválido do emissor do token"); ❷
}
if (!claims.getAudience().contains(expectedAudience)) { ❷
throw new IllegalArgumentException( ❷
"público de token de id inválido"); ❷
}
❸ Se o token de ID tiver uma declaração azp, certifique-se de que seja para o mesmo
cliente que está chamando a API.
Resumo
Os tokens com escopo permitem que os clientes tenham acesso a algumas par-
tes de sua API, mas não a outras, permitindo que os usuários deleguem acesso
limitado a aplicativos e serviços de terceiros.
O padrão OAuth2 fornece uma estrutura para clientes de terceiros se registra-
rem em sua API e negociarem o acesso com o consentimento do usuário.
Todos os clientes de API voltados para o usuário devem usar a concessão de có-
digo de autorização com PKCE para obter tokens de acesso, sejam eles aplicati-
vos da web tradicionais, SPAs, aplicativos móveis ou aplicativos de desktop. A
concessão implícita não deve mais ser usada.
O endpoint de introspecção de token padrão pode ser usado para validar um to-
ken de acesso, ou tokens de acesso baseados em JWT podem ser usados para re-
duzir as viagens de ida e volta da rede. Os tokens de atualização podem ser usa-
dos para manter a vida útil dos tokens curta sem interromper a experiência do
usuário.
O padrão OpenID Connect se baseia no OAuth2, fornecendo uma estrutura
abrangente para transferir a autenticação do usuário para um serviço dedi-
cado. Os tokens de ID podem ser usados para identificação do usuário, mas de-
vem ser evitados para acessoao controle.
1.
Em alguns países, os bancos estão sendo obrigados a fornecer acesso API seguro
para transações e serviços de pagamento para aplicativos e serviços de terceiros.
A iniciativa Open Banking do Reino Unido e os regulamentos da Diretiva Europeia
de Serviços de Pagamento 2 (PSD2) são exemplos, sendo que ambos exigem o uso
de OAuth2.
2.
Uma maneira alternativa de eliminar esse risco é garantir que qualquer token re-
cém-emitido contenha apenas os escopos que estão no token usado para chamar o
endpoint de login. Vou deixar isso como um exercício.
3.
Projetos como SELinux ( https://selinuxproject.org/page/Main_Page ) e AppArmor (
https://apparmor .net/ ) trazem controles de acesso obrigatórios para o Linux.
4.
Uma solução possível para isso é registrar dinamicamente cada instância indivi-
dual do aplicativo como um novo cliente quando ele é inicializado, para que cada
um obtenha suas próprias credenciais exclusivas. Consulte o capítulo 12 de
OAuth2 em Action (Manning, 2017) para obter detalhes.
5.
O software AS que suporta o padrão OpenID Connect pode usar o caminho /.well-
known/openid-configuration. Recomenda-se verificar os dois locais.
6.
O antigo código de status 302 Found também é usado com frequência e há pouca
diferença entre eles.
7.
Existe um método alternativo em que o cliente envia o verificador original como
desafio, mas é menos seguro.
8.
Lembre-se do capítulo 3 que as versões anteriores do TLS eram chamadas de SSL,
e essa terminologia ainda é difundida.
9.
Como você já deve esperar, existe uma proposta para permitir que o cliente indi-
que os servidores de recursos que pretende acessar: http://mng.bz/6ANG
10.
Eu propus adicionar criptografia autenticada por chave pública ao JOSE e JWT,
mas a proposta ainda é um rascunho neste estágio. Veja http://mng.bz/oRGN .