J'ai lu sur REST et il y a beaucoup de questions sur SO à ce sujet, ainsi que sur beaucoup d'autres sites et blogs. Bien que je n'ai jamais vu cette question spécifique posée ... pour une raison quelconque, je ne peux pas comprendre ce concept ...
Si je construis une API RESTful et que je souhaite la sécuriser, l'une des méthodes que j'ai vues consiste à utiliser un jeton de sécurité. Lorsque j'ai utilisé d'autres API, il y a eu un jeton et un secret partagé ... a du sens. Ce que je ne comprends pas, c'est que les demandes à une opération de service de repos sont effectuées via javascript (XHR / Ajax), ce qui empêche quelqu'un de renifler cela avec quelque chose de simple comme FireBug (ou "afficher la source" dans le navigateur) et copier la clé API, puis emprunter l'identité de cette personne à l'aide de la clé et du secret?
Réponses:
api secret n'est pas transmis explicitement, secret est utilisé pour générer un signe de la demande en cours, côté serveur, le serveur génère le signe en suivant le même processus, si les deux signes correspondent, alors la demande est authentifiée avec succès - donc seul le le signe est passé à travers la demande, pas le secret.
la source
Nous exposons une API que les partenaires ne peuvent utiliser que sur les domaines qu'ils ont enregistrés chez nous. Son contenu est en partie public (mais de préférence pour être affiché uniquement sur les domaines que nous connaissons), mais est principalement privé pour nos utilisateurs. Alors:
Pour déterminer ce qui est affiché, notre utilisateur doit être connecté avec nous, mais cela est géré séparément.
Pour déterminer où les données sont affichées, une clé API publique est utilisée pour limiter l'accès aux domaines que nous connaissons, et surtout pour garantir que les données des utilisateurs privés ne sont pas vulnérables à CSRF .
Cette clé API est en effet visible par n'importe qui, nous n'authentifions pas notre partenaire d'une autre manière, et nous n'avons pas besoin de REFERER . Pourtant, il est sécurisé:
Lorsque notre
get-csrf-token.js?apiKey=abc123
est demandé:Recherchez la clé
abc123
dans la base de données et obtenez une liste de domaines valides pour cette clé.Recherchez le cookie de validation CSRF. S'il n'existe pas, générez une valeur aléatoire sécurisée et placez-la dans un cookie de session HTTP uniquement . Si le cookie existait, obtenez la valeur aléatoire existante.
Créez un jeton CSRF à partir de la clé API et de la valeur aléatoire du cookie, puis signez-le . (Plutôt que de conserver une liste de jetons sur le serveur, nous signons les valeurs. Les deux valeurs seront lisibles dans le jeton signé, c'est très bien.)
Définissez la réponse pour qu'elle ne soit pas mise en cache, ajoutez le cookie et renvoyez un script comme:
Remarques:
Ce qui précède n'empêche pas un script côté serveur de simuler une requête, mais garantit uniquement que le domaine correspond si un navigateur le demande.
La même politique d'origine pour JavaScript garantit qu'un navigateur ne peut pas utiliser XHR (Ajax) pour charger puis inspecter la source JavaScript. Au lieu de cela, un navigateur ordinaire ne peut le charger qu'en utilisant
<script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(ou un équivalent dynamique), puis exécutera le code. Bien entendu, votre serveur ne doit pas prendre en charge le partage de ressources inter-origines ni JSONP pour le JavaScript généré.Un script de navigateur peut modifier la valeur de
document.domain
avant de charger le script ci-dessus. Mais la même politique d'origine ne permet de raccourcir le domaine en supprimant des préfixes, comme la réécrituresubdomain.example.com
justeexample.com
, oumyblog.wordpress.com
àwordpress.com
, ou dans certains navigateurs , mêmebbc.co.uk
àco.uk
.Si le fichier JavaScript est récupéré à l'aide d'un script côté serveur, le serveur recevra également le cookie. Cependant, un serveur tiers ne peut pas obliger le navigateur d'un utilisateur à associer ce cookie à notre domaine. Par conséquent, un jeton CSRF et un cookie de validation qui ont été récupérés à l'aide d'un script côté serveur ne peuvent être utilisés que par des appels côté serveur ultérieurs, pas dans un navigateur. Cependant, ces appels côté serveur n'incluront jamais le cookie utilisateur et ne peuvent donc récupérer que des données publiques. Ce sont les mêmes données qu'un script côté serveur pourrait extraire directement du site Web du partenaire.
Lorsqu'un utilisateur se connecte, définissez un cookie utilisateur de la manière que vous souhaitez. (L'utilisateur s'est peut-être déjà connecté avant la demande de JavaScript.)
Toutes les demandes d'API ultérieures au serveur (y compris les demandes GET et JSONP) doivent inclure le jeton CSRF, le cookie de validation CSRF et (s'il est connecté) le cookie utilisateur. Le serveur peut maintenant déterminer si la demande doit être approuvée:
La présence d'un jeton CSRF valide garantit que le JavaScript a été chargé à partir du domaine attendu, s'il est chargé par un navigateur.
La présence du jeton CSRF sans le cookie de validation indique une falsification.
La présence à la fois du jeton CSRF et du cookie de validation CSRF ne garantit rien: il peut s'agir d'une fausse requête côté serveur ou d'une requête valide d'un navigateur. (Il ne peut pas s'agir d'une demande d'un navigateur effectuée à partir d'un domaine non pris en charge.)
La présence du cookie utilisateur garantit que l'utilisateur est connecté, mais ne garantit pas que l'utilisateur est membre du partenaire donné, ni que l'utilisateur consulte le bon site Web.
La présence du cookie utilisateur sans le cookie de validation CSRF indique une falsification.
La présence du cookie utilisateur garantit que la demande en cours est effectuée via un navigateur. (En supposant qu'un utilisateur n'entre pas ses informations d'identification sur un site Web inconnu, et en supposant que nous ne nous soucions pas des utilisateurs qui utilisent leurs propres informations d'identification pour faire une demande côté serveur.) Si nous avons également le cookie de validation CSRF, alors ce cookie de validation CSRF était également reçu à l'aide d'un navigateur. Ensuite, si nous avons également un jeton CSRF avec une signature valide, etle nombre aléatoire dans le cookie de validation CSRF correspond à celui de ce jeton CSRF, puis le JavaScript pour ce jeton a également été reçu lors de la même demande antérieure au cours de laquelle le cookie CSRF a été défini, donc également à l'aide d'un navigateur. Cela implique également que le code JavaScript ci-dessus a été exécuté avant la définition du jeton et qu'à ce moment-là, le domaine était valide pour la clé API donnée.
Donc: le serveur peut désormais utiliser en toute sécurité la clé API du jeton signé.
Si à un moment donné le serveur ne fait pas confiance à la demande, un 403 interdit est renvoyé. Le widget peut répondre à cela en affichant un avertissement à l'utilisateur.
Il n'est pas nécessaire de signer le cookie de validation CSRF, car nous le comparons au jeton CSRF signé. Ne pas signer le cookie rend chaque requête HTTP plus courte et la validation du serveur un peu plus rapide.
Le jeton CSRF généré est valable indéfiniment, mais uniquement en combinaison avec le cookie de validation, donc efficacement jusqu'à la fermeture du navigateur.
Nous pourrions limiter la durée de vie de la signature du jeton. Nous pourrions supprimer le cookie de validation CSRF lorsque l'utilisateur se déconnecte, pour répondre à la recommandation OWASP . Et pour ne pas partager le nombre aléatoire par utilisateur entre plusieurs partenaires, on pourrait ajouter la clé API au nom du cookie. Mais même dans ce cas, il n'est pas facile d'actualiser le cookie de validation CSRF lorsqu'un nouveau jeton est demandé, car les utilisateurs peuvent naviguer sur le même site dans plusieurs fenêtres, partageant un seul cookie (qui, lors de l'actualisation, serait mis à jour dans toutes les fenêtres, après quoi le Le jeton JavaScript dans les autres fenêtres ne correspondrait plus à ce cookie unique).
Pour ceux qui utilisent OAuth, voir également OAuth et Widgets côté client , dont j'ai eu l'idée JavaScript. Pour une utilisation côté serveur de l'API, dans laquelle nous ne pouvons pas nous fier au code JavaScript pour limiter le domaine, nous utilisons des clés secrètes au lieu des clés API publiques.
la source
OPTIONS
demande pré-volée avec une clé API publique dans l'URL, le serveur peut indiquer à un navigateur quels domaines sont autorisés (ou annuler la demande). Attention cependant, certaines requêtes ne nécessitent pas de requête pré-volée, ou n'utiliseront pas du tout CORS , et que CORS a besoin d'IE8 +. Si une solution de secours Flash est utilisée pour IE7, alors peut-être qu'une certaine dynamiquecrossdomain.xml
peut aider à obtenir la même chose pour cela. Nous n'avons pas encore essayé CORS / Flash.Cette question a une réponse acceptée, mais juste pour clarifier, l'authentification secrète partagée fonctionne comme ceci:
la source
Je suppose que vous voulez dire la clé de session et non la clé API. Ce problème est hérité du protocole http et connu sous le nom de détournement de session . La «solution de contournement» normale consiste, comme sur tout site Web, à passer en https.
Pour exécuter le service REST sécurisé, vous devez activer https et probablement l'authentification du client. Mais après tout, cela dépasse l'idée REST. REST ne parle jamais de sécurité.
la source
Ce que vous voulez faire côté serveur, c'est générer un identifiant de session expirant qui est renvoyé au client lors de la connexion ou de l'inscription. Le client peut ensuite utiliser cet identifiant de session comme secret partagé pour signer les demandes suivantes.
L'identifiant de session n'est transmis qu'une seule fois et cela DOIT être via SSL.
Voir l'exemple ici
Utilisez un nonce et un horodatage lors de la signature de la demande pour éviter le détournement de session.
la source
Je vais essayer de répondre à la question dans son contexte d'origine. La question est donc "La clé secrète (API) peut-elle être placée en toute sécurité dans JavaScript?
À mon avis, c'est très dangereux car cela va à l'encontre du but de l'authentification entre les systèmes. Étant donné que la clé sera exposée à l'utilisateur, l'utilisateur peut récupérer des informations auxquelles il n'est pas autorisé. Parce que dans une communication de repos typique, l'authentification est uniquement basée sur la clé API.
Une solution à mon avis est que l'appel JavaScript passe essentiellement la demande à un composant serveur interne qui est responsable de faire un appel de repos. Le composant serveur interne, disons qu'un servlet lira la clé API à partir d'une source sécurisée telle qu'un système de fichiers basé sur des autorisations, l'insérera dans l'en-tête HTTP et effectuera l'appel de repos externe.
J'espère que ça aide.
la source