Aperçu:
Mon entreprise a développé une API à taux limité. Notre objectif est double:
- R: Créez un écosystème de développeurs solide autour de notre produit.
- B: Démontrez la puissance de notre API en l'utilisant pour piloter notre propre application.
Clarification: Pourquoi limiter le taux?
Nous évaluons limiter notre API, car nous la vendons en complément de notre produit. L'accès anonyme à notre API a un seuil très bas pour les appels d'API par heure, alors que nos clients payants sont autorisés à plus de 1000 appels par heure ou plus.
Le problème:
Notre API à débit limité est idéale pour l'éco-système des développeurs, mais pour nous permettre de la dogfood, nous ne pouvons pas l'autoriser à être limitée à la même limitation de débit. Le frontal de notre API est entièrement JavaScript, effectuant des appels Ajax directs à l'API.
La question est donc:
Comment sécuriser une API afin que la limitation de débit puisse être supprimée là où dans le processus de suppression de cette limitation de débit ne peut pas être facilement usurpée?
Solutions explorées (et pourquoi elles n'ont pas fonctionné)
Vérifiez le référent par rapport à l'en-tête d'hôte. - Imparfait car le référent est facilement truqué.
Utilisez un HMAC pour créer une signature basée sur la demande et un secret partagé, puis vérifiez la demande sur le serveur. - Imparfait car le secret et l'algorithme seraient facilement déterminés en regardant dans le JavaScript frontal.
Proxy la demande et signez la demande dans le proxy - Toujours défectueux, car le proxy lui-même expose l'API.
La question:
Je me tourne vers les esprits brillants de Stack Overflow pour présenter des solutions alternatives. comment résoudrais-tu ce problème?
la source
Réponses:
Puisque votre propre client JavaScript accède directement à l'API, n'importe qui pourra regarder ce qu'il fait et l'imiter, y compris utiliser la même clé API. Vous pouvez essayer de rendre les choses plus difficiles, par exemple en obscurcissant votre code ou en mettant divers obstacles sur le chemin, mais vous et la personne que vous essayez de restreindre avez fondamentalement le même accès. Au lieu d'essayer de créer une différence de privilèges, vous devrez construire un système dans lequel il est tout à fait normal que le client non officiel utilise tous les accès dans sa portée, mais le système est organisé de telle manière que l'utilisation officielle sur tous les clients soit plus grand.
Cela se fait souvent avec des jetons d'accès par utilisateur, par opposition à un jeton pour l'ensemble de l'application. La limite de chaque jeton doit être suffisante pour une utilisation typique de votre API, mais restrictive pour quelqu'un qui tente d'en abuser. Par exemple, 100 appels par minute peuvent être plus que suffisants pour prendre en charge la navigation classique, mais si je veux vous gratter, je ne peux pas le faire efficacement avec ce budget.
Il y aura toujours une course aux armements - je peux contourner la limite en créant de nombreux comptes d'utilisateurs de robots. Cependant, c'est un problème assez résolu si vous ajoutez simplement un captcha à votre flux d'inscription, à un petit prix pour le vrai humain. Lorsque vous entrez dans ces scénarios, tout n'est qu'un compromis entre commodité et restriction. Vous ne trouverez jamais quelque chose de totalement à l'épreuve des balles, alors concentrez-vous sur le rendre assez bon et attendez que quelqu'un vous exploite pour savoir où se trouvaient les trous.
la source
Si cela vous pose un problème, cela causera un problème à votre écosystème putatif de développeurs (par exemple, lorsqu'ils essaieront de développer une interface utilisateur alternative). Si vous mangez vraiment votre propre nourriture pour chien, faites en sorte que l'API (et la limitation de débit) fonctionne pour votre application. Voici quelques suggestions:
Ne limitez pas le taux par adresse IP. Plutôt, limiter le débit par quelque chose associé à l'utilisateur, par exemple son ID utilisateur. Appliquez la limite de débit à l'étape de l'authentification.
Concevez votre API pour que les utilisateurs n'aient pas besoin de l'appeler en continu (par exemple, donnez un appel de liste qui renvoie de nombreux résultats, plutôt qu'un appel répété qui renvoie un élément à chaque fois)
Concevez votre application Web avec les mêmes contraintes que vous attendez de votre écosystème de développeurs, c'est-à-dire assurez-vous de pouvoir la concevoir avec des taux de limitation raisonnables.
Assurez-vous que votre back-end est évolutif (de préférence horizontalement) afin que vous n'ayez pas besoin d'imposer une limitation à des niveaux si bas que cela pose un problème à une interface utilisateur.
Assurez-vous que votre étranglement a la capacité de faire face aux rafales, ainsi que de limiter les abus à long terme.
Assurez-vous que votre limitation effectue des actions sensées adaptées à l'abus que vous cherchez à supprimer. Par exemple, envisagez de faire la queue ou de retarder les abuseurs légers plutôt que de refuser la connexion. La plupart des interfaces Web n'ouvriront que quatre connexions simultanées à la fois. Si vous retardez une tentative d'ouverture d'un cinquième, vous ne rencontrerez que le cas où ils utilisent une CLI en même temps que le client Web (ou deux clients Web). Si vous retardez le n-ième appel d'API sans interruption plutôt que de l'échouer, l'utilisateur final verra les choses ralentir plutôt que s'arrêter. Si vous combinez cela avec uniquement la mise en file d'attente de N appels d'API à la fois, vous ne toucherez que les personnes qui parallélisent un grand nombre d'appels d'API, ce qui n'est probablement pas le comportement que vous souhaitez - par exemple, 100 appels d'API simultanés, alors un écart d'une heure est normalement loin pire que 100 appels API séquentiels sur une heure.
Cela n'a-t-il pas répondu à votre question? Eh bien, si vous avez vraiment besoin de faire ce que vous demandez, limitez le taux au stade de l'authentification et appliquez une limite de taux différente en fonction du groupe dans lequel votre utilisateur s'inscrit. Si vous utilisez un seul ensemble d'informations d'identification (utilisées par vos développeurs et votre équipe d'assurance qualité), vous obtenez une limite de taux plus élevée. Mais vous pouvez immédiatement voir pourquoi cela vous conduira inévitablement à voir votre écosystème des problèmes que votre équipe de développement et d'assurance qualité ne voit pas.
la source
Achetez votre produit. Devenez un client rémunéré de vous-même.
"L'accès anonyme à notre API a un seuil très bas pour les appels d'API par heure, alors que nos clients payants sont autorisés à plus de 1 000 appels par heure ou plus."
Cela permet également de tester le système du point de vue du client.
la source
Malheureusement, il n’existe pas de solution parfaite à cela.
L'approche générale consiste généralement à fournir un outrepasséesmoyen pour les clients de s'identifier (par exemple, un identifiant, une version et une clé API - par exemple), pour les clients d'enregistrer des informations les concernant qui peuvent être utilisées pour limiter l'accès (par exemple, le client est un serveur dans une plage d'adresses IP donnée, donc n'autorisez que les appelants dans cette plage; par exemple, le client est JavaScript, mais livré uniquement à une catégorie spécifique de navigateur, donc n'autorisez l'accès qu'aux requêtes HTTP qui spécifient certaines chaînes d'agent utilisateur; etc.), puis d'utiliser l'apprentissage automatique / modèle reconnaissance pour détecter une utilisation anormale qui est probablement un client usurpé, puis pour rejeter le trafic de ces clients usurpés (ou confirmer avec les clients que ces utilisations ne proviennent effectivement pas du client légitime, remplacer leurs informations d'identification usurpables, puis interdire la poursuite du trafic en utilisant l'ancien identifiants falsifiés).
Vous pouvez rendre légèrement plus difficile l'usurpation d'identité en utilisant plusieurs couches de clés. Par exemple, vous donnez un identifiant de plus longue durée qui réside sur un serveur (et qui ne peut être utilisé que dans un ensemble limité de plages d'adresses IP) pour passer un appel API qui enregistre des informations sur le client (par exemple l'agent utilisateur) et renvoie une clé côté client de plus courte durée qui est syndiquée en JavaScript pour une utilisation sur le client pour les demandes d'API côté client. Ceci est également imparfait (un spoofer pourrait émettre le même appel de serveur pour obtenir les informations d'identification), mais ce sera plus difficile si la clé API renvoyée est incluse dans JavaScript ou HTML obscurci (et changeant fréquemment) (ce qui le rendrait difficile. pour extraire de manière fiable de la réponse). Cela fournit également un moyen de détecter plus facilement l'usurpation d'identité; la clé côté client est maintenant liée à un client particulier (par exemple
la source
En supposant que l'application en question doit être ouverte publiquement, vous n'avez pas beaucoup de choix:
Choisissez une autre façon de démontrer la puissance de votre API.Par exemple, écrivez une telle application et partagez sa source, mais n'exécutez pas réellement ce code. Assurez-vous cependant qu'il est bien documenté, afin que tout le monde puisse le déployer et le voir fonctionner (sous réserve de limitation).
L'application que vous exécutez doit être refactorisée pour éviter les demandes d'API côté client et être davantage rendue par le serveur. Vous pouvez toujours dogfood votre API, mais pas de manière évidente: faites des demandes sécurisées à l'API sans limitation du côté serveur.
Ajuster la limitation de débit pour permettre à votre application de fonctionner et investissez dans l'optimisation des performances pour gérer la charge.
Et oui, ayez en premier lieu l'API de base sans ralentissement et conservez-la dans un réseau privé. Accélérez dans une couche distincte accessible au public.
la source
Pouvez-vous mettre en place une instance distincte de l'interface utilisateur et de l'API sans limitation, puis restreindre l'accès aux adresses IP provenant de votre organisation?
Par exemple, déployez le tout derrière votre pare-feu d'entreprise et attachez l'application à la même base de données que l'instance publique si vous devez partager des données entre les instances.
la source
Vous pouvez essayer de générer un identifiant de session unique, lié à une certaine adresse IP / utilisateur et une durée de vie limitée. Lorsqu'un utilisateur télécharge le code JavaScript du frontend de votre application, injectez l'ID de session généré dans le code source JavaScript. L'ID de session sera joint à chaque demande à votre API et la limite de débit est levée.
L'ID ne peut pas être simplement copié pour usurpation d'identité, car il n'est valide que pour une seule adresse IP, un seul utilisateur et une durée limitée. Un adversaire devrait donc appeler votre page et filtrer la clé de votre source JavaScript ou intercepter la requête Ajax à chaque fois qu'un nouvel utilisateur souhaite l'utiliser.
Une autre option:
Configurez un proxy pour votre propre application et utilisez l'obfuscation. Les requêtes Ajax adressées au proxy utilisent des noms différents des vrais appels API et le proxy les traduit. Ainsi, votre application n'appellerait pas
getDocument
votre véritable API, mais elle appelleraitgetFELSUFDSKJE
votre proxy. Le proxy traduira cet appel en getDocument et le transmettra à l'API à débit limité réel.Votre API réelle ne limitera pas le taux des demandes par le proxy.
Et pour que d'autres personnes n'utilisent pas votre proxy pour leur propre application, vous changez quotidiennement le schéma d'obscurcissement. Les noms d'appel masqués peuvent être générés automatiquement dans votre code source JavaScript et configurés dans le proxy.
Un client souhaitant utiliser ceci devra également suivre l'évolution de votre obfuscation pour utiliser votre proxy. Et vous pouvez toujours utiliser des en-têtes de référence et similaires pour la journalisation, afin que vous puissiez trouver des personnes utilisant votre proxy. Ou attrapez-les lors du changement du schéma d'obscurcissement.
la source
la source
Configurez plusieurs comptes et choisissez l'un d'entre eux au hasard à chaque demande, ou modifiez celui que vous utilisez toutes les heures environ. De cette façon, vous pouvez répartir la charge sur les
n
comptes, ce qui vous donne jusqu'àn
des limites fois plus élevées.Faites attention à ne pas vous arrêter accidentellement si vous essayez de trouver d'autres utilisateurs faisant cela, si cela n'est pas autorisé pour les clients.
la source