Nous allons exposer une API que les partenaires peuvent utiliser uniquement sur les domaines qu'ils ont enregistré avec nous. Son contenu est en partie publique (mais de préférence seulement être indiqué sur les domaines que nous connaissons), mais est le plus souvent privée de nos utilisateurs. Donc:
Pour déterminer ce qui est montré, notre utilisateur doit être connecté avec nous, mais c'est géré séparément.
Pour déterminer où les données sont affichées, une API publique clé est utilisée pour limiter l'accès à des domaines que nous connaissons, et surtout pour assurer le privé, les données de l'utilisateur n'est pas vulnérable à CSRF.
Cette clé API est en effet visible à tout le monde, nous n'avons pas d'authentifier notre partenaire de toute autre manière, et nous n'avez pas besoin de REFERER. Pourtant, c'est sûr:
-
Lors de notre - get-csrf-token.js?apiKey=abc123
est demandé:
Chercher la clé abc123
dans la base de données et d'obtenir une liste de validité domaines pour cette clé.
Regarder pour la validation CSRF cookie. Si elle n'existe pas, générer une sécurité aléatoire de la valeur et de la mettre dans un HTTP seule cookie de session. Si le cookie n'existe pas, obtenir existants valeur aléatoire.
Créer un jeton CSRF de la clé API et la valeur aléatoire à partir du cookie, et de le signer. (Plutôt que de garder une liste de jetons sur le serveur, nous sommes à la signature de l'valeurs. Les deux valeurs seront lisibles dans le jeton signé, c'est bien.)
-
Définir le temps de réponse pour ne pas être mis en cache, ajouter le cookie, et de renvoyer un script tel que:
var apiConfig = apiConfig || {};
if(document.domain === 'expected-domain.com'
|| document.domain === 'www.expected-domain.com') {
apiConfig.csrfToken = 'signed token with API key and random number';
// Invoke a callback if the partner wants us to
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
Notes:
Le ci-dessus n'empêche pas un serveur de script côté de simuler une demande, mais seulement de sorte que le domaine des matchs si demandé par un navigateur.
La même la politique de l'origine pour JavaScript assure qu'un navigateur ne peut pas utiliser XHR (Ajax) pour charger et puis inspectez la source JavaScript. Au lieu de cela, un navigateur ne peut le charger à l'aide de <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(ou une dynamique équivalente), puis exécutez le code. Bien sûr, votre serveur devrait pas soutenir Cross-Origin Resource sharing ni JSONP pour le JavaScript généré.
Un script de navigateur peut changer la valeur de document.domain
avant le chargement du script ci-dessus. Mais de la même origine que la politique ne permet de raccourcir le domaine par la suppression des préfixes, comme la réécriture subdomain.example.com
juste example.com
ou myblog.wordpress.com
de wordpress.com
, ou dans certains navigateurs, même bbc.co.uk
de co.uk
.
Si le fichier JavaScript est récupérée à l'aide de certains de script côté serveur, le serveur sera également obtenir le cookie. Toutefois, le serveur d'un tiers ne peut pas faire un navigateur de l'utilisateur associé cookie à notre domaine. Par conséquent, un jeton CSRF et de la validation des cookies qui ont été extraites à l'aide d'un serveur de script côté, ne peut être utilisé par la suite le côté de serveur d'appels, pas dans un navigateur. Toutefois, de telles côté serveur, les appels ne comprennent jamais de l'utilisateur cookie, et donc ne peut récupérer des données publiques. C'est les mêmes données d'un serveur de script côté pourrait gratter à partir du site du partenaire directement.
Lorsqu'un utilisateur se connecte, le jeu de certains cookie utilisateur de n'importe quelle manière que vous aimez. (L'utilisateur pourrait avoir déjà connecté avant le JavaScript a été demandée.)
-
Toutes les requêtes à l'API du serveur (y compris les OBTENIR et JSONP les demandes doivent inclure le jeton CSRF, la validation CSRF cookie, et (si connecté) l'utilisateur cookie. Le serveur peut maintenant déterminer si la demande est approuvée:
La présence d'un valide jeton CSRF assure le JavaScript a été chargé de la domaine, si chargé dans un navigateur.
La présence du jeton CSRF sans la validation de cookie indique la contrefaçon.
La présence à la fois le jeton CSRF et la validation CSRF cookie ne permet pas d'assurer quoi que ce soit: ce pourrait être soit un faux serveur côté demande, ou d'une demande valide à partir d'un navigateur. (Il ne pouvait pas être une demande à partir d'un navigateur fabriqué à partir d'un domaine non pris en charge.)
La présence du cookie utilisateur garantit à l'utilisateur est connecté, mais ne garantit pas que l'utilisateur est un membre de la partenaire, ni que l'utilisateur consulte le site web correct.
La présence de l'utilisateur cookie sans la validation CSRF cookie indique la contrefaçon.
-
La présence de l'utilisateur cookie fait en sorte que la demande actuelle est faite par le biais d'un navigateur. (En supposant que l'utilisateur ne serait pas entrer leurs informations d'identification sur un site inconnu, et en supposant que nous ne nous soucions pas les utilisateurs à l'aide de leurs propres informations d'identification pour faire un serveur côté de la demande). Si nous aussi ont la validation CSRF cookie, alors que la validation CSRF cookie a été également reçu l'aide d'un navigateur. Ensuite, si nous avons également avoir un jeton CSRF avec une signature valide, et le nombre aléatoire dans la validation CSRF cookie correspond à celui que le jeton CSRF, puis le JavaScript pour que le jeton a également été reçu au cours de cette même demande antérieure au cours de laquelle le CSRF cookie a été définie, et donc également à l'aide d'un navigateur. Ensuite, cela implique également le code JavaScript ci-dessus a été exécuté avant que le jeton a été définie, et qu'à cette époque, le domaine a été valable pour la clé API.
Donc: le serveur peut maintenant l'utiliser en toute sécurité la clé API à partir de la signature de jeton.
À tout moment, si le serveur ne fait pas confiance à la demande, puis un 403 Forbidden est retourné. Le widget peut répondre que par l'apparition d'un avertissement à l'utilisateur.
Il n'est pas tenu de signer la validation CSRF cookie, que nous sommes en la comparant à la signature de jeton CSRF. Pas de signer le cookie permet de chaque requête HTTP, plus courte, et le serveur de validation un peu plus vite.
L'généré jeton CSRF est valide indéfiniment, mais seulement en combinaison avec la validation de cookie, donc effectivement, jusqu'à la fermeture du navigateur.
On pourrait limiter la durée de vie du jeton de signature. On pourrait supprimer la validation CSRF cookies lorsque l'utilisateur se déconnecte, pour répondre à l'OWASP recommandation. Et de ne pas partager les par utilisateur nombre aléatoire entre plusieurs partenaires, on pourrait ajouter la clé API pour le nom de cookie. Mais même alors, on ne peut pas facilement actualiser la validation CSRF cookie lorsqu'un nouveau jeton est demandé, les internautes naviguant sur le même site en plusieurs fenêtres, à l'aide d'un seul cookie.
Pour ceux qui utilisent le protocole OAuth, voir aussi OAuth et Côté Client Widgets, à partir de laquelle j'ai obtenu le JavaScript idée. Pour le côté serveur de l'utilisation de l'API, dans lequel on ne peut s'appuyer sur le code JavaScript pour limiter le domaine, nous sommes à l'aide de clés secrètes au lieu de l'API publique clés.