13 Securing IoT APIs - API Security in Action
13 Securing IoT APIs - API Security in Action
pacote com.manning.apisecurityinaction;
import org.dalesbred.Database;
import org.dalesbred.annotation.DalesbredInstantiator;
import org.h2.jdbcx.JdbcConnectionPool;
importar software.pando.crypto.nacl.SecretBox;
importar java.io.*;
importar java.security.Key;
import java.util.Opcional;
@DalesbredInstantiator ❷
public Device(String deviceId, String fabricante,
Modelo de string, byte[] criptografadoPsk) {
this.deviceId = deviceId;
this.manufacturer = fabricante;
this.model = modelo;
this.encryptedPsk = criptografadoPsk;
}
Agora você pode preencher o banco de dados com perfis de dispositivo. A Lista-
gem 13.2 mostra como inicializar o banco de dados com um exemplo de perfil de
dispositivo e PSK criptografado. Assim como nos capítulos anteriores, você pode
usar um banco de dados H2 na memória temporário para armazenar os detalhes
do dispositivo, porque isso facilita o teste. Em uma implantação de produção, você
usaria um servidor de banco de dados ou diretório LDAP. Você pode carregar o
banco de dados na biblioteca Dalesbred que você usou desde o capítulo 2 para
simplificar as consultas. Em seguida, você deve criar a tabela para conter os perfis
de dispositivo, neste caso com atributos de string simples ( VARCHAR em SQL) e um
atributo binário para manter o PSK criptografado. Você poderia extrair essas ins-
truções SQL em um arquivo schema.sql separado, como fez no capítulo 2, mas
como há apenas uma única tabela, usei strings literais. Abra o arquivo Device.java
novamente e inclua o novo método da listagem para criar o banco de dados de
dispositivo de exemplo.
❶ Use o método findOptional com sua classe Device para carregar dispositivos.
Agora que você tem alguns detalhes do dispositivo, pode usá-los para autenticar
dispositivos e executar o controle de acesso com base nessas identidades de dispo-
sitivo, o que você fará nas seções 13.1.2 e13.1.3.
{
"iss":"https://example.com/devices", ❶
"iat":1590139506, ❶
"exp":1905672306, ❶
"sub":"ada37d7b-e895-4d55-9571-4df602e60c27", ❶
"psk ":" jZvara1OnqqBZrz1HtvHBCNjXvCJptEuIAAAAJInAtaLFnYna9K0WxX4_ ❷
➥ IGPyztb8VUwo0CI_UmqDQgm" ❷
}
❷ Adicione um PSK criptografado que pode ser usado para se comunicar com o
dispositivo.
Isso pode ser mais escalável do que um banco de dados se você tiver muitos dis-
positivos, mas torna mais difícil atualizar detalhes incorretos ou alterar chaves.
Um meio-termo é fornecido pelas técnicas de atestação discutidas no capítulo 12,
nas quais um certificado inicial e uma chave são usados para provar a marca e o
modelo de um dispositivo quando ele se registra pela primeira vez em uma rede
e, em seguida, negocia uma chave específica do dispositivo para usar a partir de
entãosobre.
13.1.3 Autenticando na camada de transporte
Sehá uma conexão direta entre um dispositivo e a API que está acessando, então
você pode usar mecanismos de autenticação fornecidos pelo protocolo de segu-
rança da camada de transporte. Por exemplo, a chave pré-compartilhada (PSK)
conjuntos de cifras para TLS descritos no capítulo 12 fornecem autenticação mú-
tua do cliente e do servidor. A autenticação de certificado de cliente pode ser
usada por dispositivos mais capazes, assim como você fez no capítulo 11 para cli-
entes de serviço. Nesta seção, veremos a identificação de dispositivos usando a
autenticação PSK.
pacote com.manning.apisecurityinaction;
importar org.bouncycastle.tls.TlsPSKIdentityManager;
import org.dalesbred.Database;
importar java.security.Key;
importar estático java.nio.charset.StandardCharsets.UTF_8;
public class DeviceIdentityManager implementa TlsPSKIdentityManager {
banco de dados de banco de dados final privado;
Chave final privada pskDecryptionKey; ❶
❸ Converta a dica de identidade PSK em uma string UTF-8 para usar como a identi-
dade do dispositivo.
Embora agora você esteja autenticando o dispositivo com base em um PSK ane-
xado ao seu perfil de dispositivo, esse perfil de dispositivo não é exposto à API
após a conclusão do handshake. O Bouncy Castle não fornece um método público
para obter a identidade PSK associada a uma conexão, mas é fácil expor você
mesmo adicionando um novo método ao PSKTlsServer , como mostra a Lista-
gem 13.6. Uma variável protegida dentro do servidor contém a TlsCon-
text classe, que contém informações sobre a conexão (o servidor suporta apenas
um único cliente por vez). A identidade PSK é armazenada dentro da
SecurityParameters classepara a conexão. Abra o arquivo PskServer.java e
adicione o novo método destacado em negrito na listagem. Você pode recuperar a
identidade do dispositivo depois de receber uma mensagem ligando para:
String getPeerDeviceIdentity() { ❶
return new String(context.getSecurityParametersConnection() ❷
.getPSKIdentity(), UTF_8); ❷
}
};
O servidor da API pode usar essa identidade de dispositivo para procurar permis-
sões para esse dispositivo, usando as mesmas técnicas de controle de acesso base-
adas em identidade usadas para usuáriosdentrocapítulo 8.
questionário
Sea conexão do dispositivo à API deve passar por diferentes protocolos, conforme
descrito no capítulo 12, a autenticação de dispositivos na camada de transporte
não é uma opção. No capítulo 12, você aprendeu como proteger solicitações e res-
postas de API de ponta a ponta usando criptografia autenticada comRepresenta-
ção Concisa de Objetos Binários (CBOR) Assinatura e criptografia de objetos(COSE)
ou NaCl's CryptoBox . Esses formatos de mensagem criptografada garantem que
as solicitações não sejam adulteradas, e o servidor da API pode ter certeza de que
a solicitação foi originada do dispositivo que afirma ser. Adicionando um identifi-
cador de dispositivo à mensagem como dados associados. 1 , que você lembrará
do capítulo 6, é autenticado, mas não criptografado, a API pode pesquisar o perfil
do dispositivo para encontrar a chave para descriptografar e autenticar as mensa-
gens desse dispositivo.
Infelizmente, isso não é suficiente para garantir que as solicitações de API real-
mente vieram desse dispositivo, portanto, é perigoso tomar decisões de controle
de acesso com base apenas no código de autenticação de mensagem (MAC) usado
para autenticar a mensagem. O motivo é que as solicitações de API podem ser
capturadas por um invasor e reproduzidas posteriormente para executar a
mesma ação novamente em um momento posterior, conhecido como ataque de
repetição. Por exemplo, suponha que você seja o líder de uma organização ma-
ligna clandestina com a intenção de dominar o mundo. Um dispositivo de monito-
ramento em sua usina de enriquecimento de urânio envia uma solicitação de API
para aumentar a velocidade de uma centrífuga. Infelizmente, o pedido é intercep-
tado por um agente secreto, que repete o pedido centenas de vezes, e a centrífuga
gira muito rápido, causando danos irreparáveis e atrasando seus planos covardes
por vários anos.
Para evitar ataques de repetição, a API precisa garantir que uma solicitação veio
de um cliente legítimo e é recente. A atualização garante que a mensagem seja re-
cente e não tenha sido repetida e é fundamental para a segurança ao tomar deci-
sões de controle de acesso com base na identidade do cliente. O processo de iden-
tificação com quem um servidor de API está se comunicando é conhecido como
autenticação de entidade.
OBSERVAÇÃO OSCORE pode ser usado como alternativa aos protocolos de se-
gurança da camada de transporte, como DTLS, ou em adição a eles. As duas abor-
dagens são complementares e a melhor segurança vem da combinação de ambas.
OSCORE não criptografa todas as partes das mensagens que estão sendo trocadas,
então TLS ou DTLS fornecem proteção adicional, enquanto OSCORE garante segu-
rança de ponta a ponta.
Para usar o OSCORE, o cliente e o servidor devem manter uma coleção de estado,
conhecida como contexto de segurança, durante suas interações entre si. O con-
texto de segurança consiste em três partes, mostradas na figura 13.4:
DERIVANDO O CONTEXTO
A chave HKDF para OSCORE pode então ser calculada a partir da chave mestra e
do sal mestre da seguinte forma:
var hkdfKey = HKDF.extract(masterSalt, masterKey);
importar COSE.*;
import com.upokecenter.cbor.CBORObject;
importar org.bouncycastle.jce.provider.BouncyCastleProvider;
importar java.nio.*;
importar java.security.*;
AVISO Não use esta chave mestra e sal mestre em um aplicativo real! Novas cha-
ves devem ser geradas para cada dispositivo.
GERANDO NONCES
A matriz resultante é então combinada com o Common IV usando XOR bit a bit,
usando o seguinte método:
private static byte[] xor(byte[] xs, byte[] ys) {
for (int i = 0; i < xs.length; ++i) ❶
xs[i] ^= ys[i]; ❶
retornar xs; ❷
}
Uma vezSe você derivou o nonce por mensagem, pode criptografar uma mensa-
gem OSCORE, conforme mostrado na Listagem 13.12, que se baseia no exemplo da
seção C.4 da especificação OSCORE. As mensagens OSCORE são codificadas como
COSE_Encrypt0 estruturas, nas quais não há informações explícitas sobre o des-
tinatário. O IV parcial e o ID do remetente são codificados na mensagem como ca-
beçalhos desprotegidos, com o ID do remetente usando o cabeçalho COSE Key ID
(KID) padrão. Embora marcados como desprotegidos, esses valores são realmente
autenticados porque o OSCORE exige que eles sejam incluídos em um COSE de da-
dos autenticados adicionais externosestrutura, que é um array CBOR com os se-
guintes elementos:
varassociatedData = CBORObject.NewArray(); ❺
dadosassociados.Add(1); ❺
dadosassociados.Add(algorithm.AsCBOR()); ❺
associadoData.Add(senderId); ❺associatedData.Add
(partialIv); ❺
dadosassociados.Adicionar(novo byte[0]); ❺
message.setExternal(associatedData.EncodeToBytes()); ❺
Security.addProvider(new BouncyCastleProvider()); ❻
message.encrypt(senderKey.getEncoded()); ❻
O destinatário é responsável por verificar se o Partial IV não foi visto antes para
evitar ataques de repetição. Quando o OSCORE é transmitido por um protocolo
confiável, como HTTP, isso pode ser obtido mantendo o controle do último IV par-
cial recebido e garantindo que todas as novas mensagens sempre usem um nú-
mero maior. Para protocolos não confiáveis, como CoAP sobre UDP, onde as men-
sagens podem chegar fora de ordem, você pode usar o algoritmo do RFC 4303 (
http://mng.bz/4BjV). Essa abordagem mantém uma janela de números de sequên-
cia permitidos entre um valor mínimo e máximo que o destinatário aceitará e re-
gistra explicitamente quais valores nesse intervalo foram recebidos. Se o destina-
tário for um cluster de servidores, como uma API típica hospedada em nuvem,
esse estado deverá ser sincronizado entre todos os servidores para evitar ataques
de repetição. Como alternativa, o balanceamento de carga permanentepode ser
usado para garantir que as solicitações do mesmo dispositivo sejam sempre entre-
gues à mesma instância do servidor, conforme mostrado na figura 13.5, mas isso
pode ser problemático em ambientes onde os servidores são frequentemente adi-
cionados ou removidos. A Seção 13.1.5 discute uma abordagem alternativa para
evitar ataques de repetição que podem ser eficazes paraDESCANSOAPIs.
A especificação HTTP requer que os métodos somente leitura GET, HEAD e OPTI-
ONS, juntamente com as solicitações PUT e DELETE, sejam todos idempotentes.
Apenas os métodos POST e PATCH geralmente não são idempotentes.
ATENÇÃO Mesmo se você se limitar a requisições PUT em vez de POST, isso não
significa que suas requisições estão sempre protegidas contra replay.
O problema é que a definição de idempotência não diz nada sobre o que acontece
se outra solicitação ocorrer entre a solicitação original e a repetição. Por exemplo,
suponha que você envie uma solicitação PUT atualizando uma página em um site,
mas perde sua conexão de rede e não sabe se a solicitação foi bem-sucedida ou
não. Como a solicitação é idempotente, você a envia novamente. Sem que você
saiba, um de seus colegas, entretanto, enviou uma solicitação DELETE porque o
documento continha informações confidenciais que não deveriam ter sido publi-
cadas. Sua solicitação PUT reproduzida chega depois e o documento é ressusci-
tado, com dados confidenciais e tudo. Um invasor pode reproduzir solicitações
para restaurar uma versão antiga de um recurso, mesmo que todas as operações
sejam individualmente idempotentes.
Felizmente, existem vários mecanismos que você pode usar para garantir que ne-
nhuma outra solicitação tenha ocorrido nesse meio tempo. Muitas atualizações de
um recurso seguem o padrão de primeiro ler a versão atual e, em seguida, enviar
uma versão atualizada. Você pode garantir que ninguém alterou o recurso desde
que você o leu usando um dos dois mecanismos HTTP padrão:
AVISO Embora um hash criptográfico possa ser atraente como uma ETag, isso
significa que a ETag reverterá para um valor anterior se o conteúdo o fizer. Isso
permite que um invasor reproduza quaisquer solicitações antigas com uma ETag
correspondente. Você pode evitar isso incluindo um contador ou registro de data
e hora no cálculo da ETag para que a ETag seja sempre diferente, mesmo que o
conteúdo seja o mesmo.
resposta.status(200); ❸
response.header("ETag", String.valueOf(expectedEtag + 1)); ❸
response.type("texto/simples");
retornar "OK";
});
O mecanismo ETag também pode ser usado para impedir a repetição de uma soli-
citação PUT destinada a criar um recurso que ainda não existe. Como o recurso
não existe, não há ETag ou data da última modificação existente para incluir. Um
invasor pode reproduzir essa mensagem para substituir uma versão posterior do
recurso pelo conteúdo original. Para evitar isso, você pode incluir um cabeçalho
If-None-Match com o valor especial * , que informa ao servidor para rejeitar a so-
licitação se houver alguma versão existente desse recurso.
Neste exemplo, os cabeçalhos são codificados como um mapa CBOR, que é então
combinado com o corpo da solicitação e uma indicação do método HTTP esperado
para criar o objeto geral da solicitação. Todo o objeto é então criptografado e au-
tenticado usando NaCl's CryptoBox funcionalidade. O OSCORE, discutido na se-
ção 13.1.4, é um exemplo de protocolo fim-a-fim usando objetos de requisição. Os
objetos de requisição no OSCORE são mensagens CoAP criptografadas com COSE.
request.attribute("decryptedRequest", cbor.get("body")); ❹
});
questionário
Por todo Neste livro, o OAuth2 surgiu repetidamente como uma abordagem co-
mum para proteger APIs em muitos ambientes diferentes. O que começou como
uma maneira de fazer autorização delegada em aplicativos da Web tradicionais se
expandiu para abranger aplicativos móveis, APIs de serviço a serviço e microsser-
viços. Portanto, não deve surpreender que também esteja sendo aplicado para
proteger APIs na IoT. É especialmente adequado para aplicações de IoT do consu-
midor em casa. Por exemplo, uma smart TV pode permitir que os usuários façam
login em serviços de streaming para assistir a filmes ou ouvir música ou visuali-
zar atualizações de fluxos de mídia social. Estes são adequados para OAuth2, por-
que envolvem um ser humano que delega parte de sua autoridade a um disposi-
tivo para uma finalidade bem definida.
Mas as abordagens tradicionais para obter autorização podem ser difíceis de usar
em um ambiente IoT por vários motivos:
O dispositivo pode não ter uma tela, teclado ou outros recursos necessários
para permitir que um usuário interaja com o servidor de autorização para
aprovar o consentimento. Mesmo em um dispositivo mais capaz, como uma
smart TV, digitar nomes de usuário longos ou senhas em um pequeno controle
remoto pode ser demorado e irritante para os usuários. A Seção 13.2.1 discute a
concessão de autorização do dispositivoque visa resolver este problema.
Os formatos de token e os mecanismos de segurança usados pelos servidores de
autorização geralmente são fortemente focados em clientes de navegador da
web ou aplicativos móveis e não são adequados para dispositivos mais restri-
tos. A estrutura ACE-OAuth discutida na seção 13.2.2 é uma tentativa de adaptar
o OAuth2 para tais ambientes restritos.
DEFINIÇÃO ACE-OAuth (Autorização para Ambientes Restritos usando OAuth2)
é uma especificação de estrutura que adapta OAuth2 para dispositivos restritos.
Para iniciar o fluxo, o dispositivo primeiro faz uma solicitação POST para um
novo endpoint de autorização de dispositivo no AS, indicando o escopo do token
de acesso necessário e autenticando usando suas credenciais de cliente. O AS re-
torna três detalhes na resposta:
import org.json.JSONObject;
importar java.net.*;
importar java.net.http.*;
importar java.net.http.HttpRequest.BodyPublishers;
importar java.net.http.HttpResponse.BodyHandlers;
importar java.util.concurrent.TimeUnit;
importar estático java.nio.charset.StandardCharsets.UTF_8;
if (response.statusCode() != 200) { ❷
throw new RuntimeException("Resposta incorreta do AS: " + ❷
response.body()); ❷
} ❷
return new JSONObject(response.body()); ❸
}
O dispositivo original que solicitou autorização não é notificado de que o fluxo foi
concluído. Em vez disso, ele deve pesquisar periodicamente o endpoint do token
de acesso no AS, passando o código do dispositivo recebido na solicitação inicial,
conforme mostrado na Listagem 13.17. Este é o mesmo endpoint de token de
acesso usado nos outros tipos de concessão OAuth2 discutidos no capítulo 7, mas
você define o grant_type parâmetropara
urn:ietf:params:oauth:grant-type:device_code
A Listagem 13.18 mostra como lidar com o fluxo de autorização total no cliente
com base nos métodos anteriores. Abra o arquivo DeviceGrantClient.java nova-
mente e adicione o método principal dolistagem.
DICA Se você quiser testar o cliente, o ForgeRock Access Management(AM) o pro-
duto oferece suporte à concessão de autorização do dispositivo. Siga as instruções
no apêndice A para configurar o servidor e depois as instruções em http://mng.bz/
X0W6 para configurar a concessão de autorização do dispositivo. AM implementa
uma versão de rascunho mais antiga do padrão e requer um
response_type=device _code parâmetro extrana solicitação inicial para ini-
ciar o fluxo.
while (true) { ❸
Thread.sleep(TimeUnit.SECONDS.toMillis(interval)); ❸
json = pollAccessTokenEndpoint(clientId, deviceCode); ❸
var erro = json.optString("erro", nulo);
if (erro != nulo) {
alternar (erro) {
case "slow_down": ❹
System.out.println("Slowing down"); ❹
intervalo += 5; ❹
parar;
case "authorization_pending": ❺
System.out.println("Ainda esperando!"); ❺
parar;
predefinição:
System.err.println("Falha na autorização: " + erro);
System.exit(1);
parar;
}
} senão {
System.out.println("Token de acesso: " + ❻
json.getString("access_token")); ❻
parar;
}
}
}
❺ Caso contrário, continue esperando até que uma resposta seja recebida.
13.3.2 ACE-OAuth
Algumos dispositivos podem nunca precisar interagir com um usuário, mas para
alguns aplicativos de IoT essa é uma preocupação principal. Por exemplo, muitas
empresas agora operam armários inteligentes onde as mercadorias encomenda-
das online podem ser entregues para coleta posterior. O usuário chega mais tarde
e usa um aplicativo em seu smartphone para enviar uma solicitação para abrir o
armário. Os dispositivos usados em implantações industriais de IoT podem funci-
onar de forma autônoma na maior parte do tempo, mas ocasionalmente precisam
de manutenção por um técnico humano. Seria frustrante para o usuário se ele
não pudesse obter sua última compra porque o armário não pode se conectar a
um serviço de nuvem para autenticá-lo, e um técnico geralmente só está envol-
vido quando algo deu errado, então você não deve presumir que os serviços de
rede estarão disponíveis nesta situação.
A solução é disponibilizar as credenciais do usuário para o dispositivo para que
ele possa autenticar o usuário localmente. Isso não significa que o hash da senha
do usuário deva ser transmitido ao dispositivo, pois isso seria muito perigoso: um
invasor que interceptasse o hash poderia realizar um ataque de dicionário off-
line para tentar recuperar a senha. Pior ainda, se o invasor comprometer o dispo-
sitivo, ele poderá simplesmente interceptar a senha diretamente enquanto o
usuário a digita. Em vez disso, a credencial deve ser de curta duração e limitada
apenas às operações necessárias para acessar esse dispositivo. Por exemplo, um
usuário pode receber um código único que pode ser exibido em seu smartphone
como um código QR que o armário inteligente pode escanear. O mesmo código é
hash e enviado para o dispositivo, que pode comparar o hash com o código QR e,
se forem iguais, abre o armário,
Figura 13.9 Códigos únicos podem ser enviados periodicamente para um disposi-
tivo IoT, como um armário seguro. Um hash seguro do código é armazenado local-
mente, permitindo que o armário autentique os usuários, mesmo que não consiga
entrar em contato com o serviço de nuvem naquele momento.
Para que essa abordagem funcione, o dispositivo deve estar online periodica-
mente para baixar novas credenciais. Um formato de token autocontido e assi-
nado pode superar esse problema. Antes de sair para atender um dispositivo em
campo, o técnico pode se autenticar em um servidor de autorização central e re-
ceber um token de acesso OAuth2 ou token OpenID Connect ID. Esse token pode
incluir uma chave pública ou uma credencial temporária que pode ser usada para
autenticar localmente o usuário. Por exemplo, o token pode ser vinculado a um
certificado de cliente TLS, conforme descrito no capítulo 11, ou a uma chave
usando os tokens CWT PoP mencionados na seção 13.3.2. Quando o técnico chega
para atender o dispositivo, ele pode apresentar o token de acesso para acessar as
APIs do dispositivo por meio de uma conexão local, como Bluetooth Low
Energy(BLE). A API do dispositivo pode verificar a assinatura no token de acesso e
verificar o escopo, emissor, público, tempo de expiração e outros detalhes. Se o to-
ken for válido, as credenciais incorporadas podem ser usadas para autenticar o
usuário localmente para permitir o acesso de acordo com as condições anexadas
aosímbolo.
Formatos de token de acesso independentes também podem ser usados para per-
mitir a autorização off-line. Um exemplo simples é o escopo incluído em um token
de acesso, que permite que um dispositivo off-line determine quais operações de
API um cliente deve ter permissão para chamar. Condições mais complexas po-
dem ser codificadas como advertências usando um formato de token de biscoito,
discutido no capítulo 9. Suponha que você tenha usado seu smartphone para re-
servar um carro alugado. Um token de acesso em formato macaroon é enviado
para o seu telefone, permitindo que você desbloqueie o carro transmitindo o to-
ken para o carro via BLE, como no exemplo no final da seção 13.4.1. Mais tarde,
você dirige o carro para um evento noturno em um hotel de luxo em um local iso-
lado, sem cobertura de rede celular. O hotel oferece estacionamento com mano-
brista, mas você não confia no atendente, então você só quer permitir que eles te-
nham uma capacidade limitada de dirigir o carro caro que você alugou. Como seu
token de acesso é um biscoito, você pode simplesmente anexar advertências a ele,
restringindo o token a expirar em 10 minutos e permitir que o carro seja condu-
zido apenas em um raio de um quarto de milha do hotel.
Os macaroons são uma ótima solução para autorização off-line, pois as advertên-
cias podem ser adicionadas por dispositivos a qualquer momento sem qualquer
coordenação e podem ser verificadas localmente por dispositivos sem a necessi-
dade de entrar em contato com um serviço central. As advertências de terceiros
também podem funcionar bem em um aplicativo IoT, porque exigem que o cliente
obtenha prova de autorização da API de terceiros. Essa autorização pode ser ob-
tida antecipadamente pelo cliente e posteriormente verificada pelo dispositivo,
verificando a descarga do macaroon, sem a necessidade de contato direto com o
terceiro.
questionário
6. Qual concessão de autorização OAuth pode ser usada em dispositivos que não
possuem recursos de entrada do usuário?
1. A concessão de credenciais do cliente
2. A concessão do código de autorização
3. A concessão de autorização do dispositivo
4. A concessão de senha do proprietário do recurso
A resposta está no final do capítulo.
1. Falso. O PSK pode ser qualquer sequência de bytes e pode não ser uma string
válida.
2. d. o ID é autenticado durante o aperto de mão, portanto, você só deve confiar
nele após a conclusão do aperto de mão.
3. d. A autenticação de entidade requer que as mensagens sejam novas e não te-
nham sido reproduzidas.
4. b, c e d.
5. uma.
6. c. O dispositivoautorizaçãoconceder.
Resumo
1.
Uma das poucas desvantagens do NaCl CryptoBox e SecretBox das APIs é que
eles não permitem dados associados autenticados.
2.
Se o servidor puder determinar que o estado atual do recurso corresponde ao es-
tado solicitado, ele também poderá retornar um código de status de sucesso como
se a solicitação fosse bem-sucedida neste caso. Mas, neste caso, a solicitação é re-
almente idempotente de qualquer maneira.
3.
Estranhamente, a concessão de autorização do dispositivo ainda não é suportada.