Django-tastypie: Besoin d'une valeur par défaut beaucoup plus sûre: `DjangoAuthorization` ne devrait pas autoriser l'accès` read` à tous les objets du modèle

Créé le 6 janv. 2016  ·  10Commentaires  ·  Source: django-tastypie/django-tastypie

En regardant tastypie/authorization.py (environ comme 133 - branche master le 1/4/2016), la valeur par défaut, à la fois read_list et read_details bypass user.has_perm() chèque, ce qui est assez dangereux et est un mauvais défaut.

L'administrateur par défaut de Django n'est pas conventionnel. Donc, je pouvais voir comment c'était mal interprété.

https://docs.djangoproject.com/es/1.9/topics/auth/default/#permissions -and-autorisation

The Django admin site uses permissions as follows:
*   ... 
* Access to view the change list, view the “change” form and change an object is limited to users with the “change” permission for that type of object.

Essentiellement, "change_xyz" est le code d'autorisation pour "lire" et "mettre à jour". Je pense que le meilleur défaut serait de suivre l'administrateur de Django:

diff --git a/tastypie/authorization.py b/tastypie/authorization.py
index 1d6f5aa..44b2d56 100644
--- a/tastypie/authorization.py
+++ b/tastypie/authorization.py
@@ -151,22 +151,14 @@ class DjangoAuthorization(Authorization):
         return model_klass

     def read_list(self, object_list, bundle):
-        klass = self.base_checks(bundle.request, object_list.model)
-
-        if klass is False:
-            return []
+        # By default, follows `ModelAdmin` "convention" to use `app.change_model`
+        # `django.contrib.auth.models.Permission` for both viewing and updating.
+        # https://docs.djangoproject.com/es/1.9/topics/auth/default/#permissions-and-authorization

-        # GET-style methods are always allowed.
-        return object_list
+        return self.update_list(object_list, bundle)

     def read_detail(self, object_list, bundle):
-        klass = self.base_checks(bundle.request, bundle.obj.__class__)
-
-        if klass is False:
-            raise Unauthorized("You are not allowed to access that resource.")
-
-        # GET-style methods are always allowed.
-        return True
+        return self.update_detail(object_list, bundle)

bug immediate

Commentaire le plus utile

Lorsque vous apportez des modifications de rupture de production, pouvez-vous au moins refléter cela dans la gestion des versions?
La gestion des versions x.y.z Tastypie ressemble beaucoup à ce que la plupart des gens attendent , c'est-à-dire généralement:

Étant donné un numéro de version MAJOR.MINOR.PATCH, incrémentez:
..
Version PATCH lorsque vous effectuez des corrections de bogues rétrocompatibles.

Je viens de passer une heure très inconfortable à retracer cela lors d'un nouveau déploiement de production.

Tous les 10 commentaires

J'apprécie que cela soit déjà fusionné, mais je suis toujours en désaccord avec cela. Avant d'ouvrir une nouvelle demande, voici ma préoccupation:

Ce changement casse malheureusement le code existant et est donc incompatible en arrière (auparavant, toutes les requêtes GET passaient DjangoAuthorization). Pour corriger son code, les deux seules options sont soit de donner à tous les utilisateurs la permission de «modifier» (mauvaise), soit de sous-classer DjangoAuthorization pour une implémentation personnalisée des actions de lecture (potentiellement beaucoup de travail). Était-ce l'intention?

J'apprécie le raisonnement derrière cela dans le contexte d'administration de django, mais je doute que définir «read» comme l'équivalent de «change» dans un contexte d'API soit une hypothèse par défaut raisonnable car ce n'est pas le comportement attendu. Après tout, si GET est une méthode autorisée avec DjangoAuthorization, pourquoi refuserait-il l'accès sur la base du fait que l'utilisateur n'a pas l'autorisation change ?

Je propose la mise en œuvre alternative suivante:

_pour read_detail_

  • si le modèle a une permission view , vérifiez que (= amélioration pour ceux qui en ont besoin)
  • s'il n'y a pas view permission

_for read_list_

  • si le modèle a une permission list , vérifiez que (= amélioration pour ceux qui en ont besoin)
  • s'il n'y a pas list permission

De cette façon, tastypie ajoute une valeur par défaut compatible avec les paramètres d'autorisation par défaut de Django tout en offrant un moyen facile de s'améliorer en ajoutant des autorisations d'affichage et de liste pour ceux qui en ont besoin, à moins d'écrire une implémentation personnalisée de DjangoAuthorization.

Au moins, il devrait y avoir un moyen de spécifier l'autorisation par défaut:

DjangoAuthorization(read_permission='view', # applies to both list, detail if not spec'd
                    read_list_permission='view', # list only
                    read_detail_permission='view') # detail only
# while we're at it, why not add the other permissions too
DjangoAuthorization(change_permission='change',
                    delete_permission='delete',
                    add_permission='add', 
                    # ... add options as per above for each
                    # <action>_<level> permission where 
                    # action is `change,delete,add,read`,  level is `list,detail`)

@SeanHayes sera celui qui décidera.

Juste mon avis ici, je pense que c'était un problème de sécurité pour permettre la lecture par défaut. Je ne m'y attendais pas du tout, jusqu'à ce que je sois très proche de la production. Je pense que la rupture de la compatibilité descendante est nécessaire dans ce contexte.

Il semblerait que votre suggestion nécessite de changer le passage des paramètres en DjangoAuthorization à votre code existant, dans ce cas, je pense qu'il est juste plus clair d'appeler la classe autre chose.

Considérez, read_permission='view' case, voici peut-être exactement ce dont vous avez besoin. Je ne vois pas pourquoi c'est moins optimal que

class ModifiedDjangoAuthorization(DjangoAuthorization):
    READ_PERM_CODE = 'view'

Si vous souhaitez en changer d'autres, remplacez simplement les méthodes. Le changement a en fait été conçu pour le rendre très facile à faire.

class ModifiedDjangoAuthorization(DjangoAuthorization):
    def delete_list(self, object_list, bundle):
        return self.perm_list_checks(bundle.request, 'del', object_list)

    def delete_detail(self, object_list, bundle):
        return self.perm_obj_checks(bundle.request, 'del', bundle.obj)

Le changement a pris en compte les modifications et a facilité les choses. Je ne pense pas nécessairement que cela devrait être fait en tant que paramètres init.

Je pense que c'était un problème de sécurité d'autoriser la lecture par défaut.

Je ne remets pas en question l'intention du problème initial. Il suffit de souligner que l'implémentation fusionnée brise le code et les hypothèses existants des gens sans le dire et sans option efficace pour revenir.

Il semble que votre suggestion nécessite de changer les paramètres transmis à DjangoAuthorization en votre code existant,

Si vous examinez à nouveau ma solution proposée, ce que je préconise est de donner aux gens des options avec une valeur par défaut sûre et rétrocompatible. Aucune modification ne serait nécessaire dans le code de l'utilisateur dans ce cas.

Je pense que la rupture de la compatibilité descendante est nécessaire dans ce contexte.

Je ne suis pas d'accord. Le changement tel qu'il est actuellement fusionné rompt non seulement la rétrocompatibilité, mais introduit également un problème de sécurité potentiel beaucoup plus important dans la mesure où la manière évidente (impliquée par l'implémentation actuelle) est d'attribuer l'autorisation de modification à tous les utilisateurs qui devraient être autorisés à GET.

Franchement, je ne vois pas comment l'autorisation change pour les actions de lecture augmente la sécurité car en même temps cette autorisation autorise également PUT. Le mélange des autorisations pour différentes actions ne semble pas un bon choix.

Malheureusement, votre proposition ModifiedDjangoAuthorization ne fera pas l'affaire à moins que vous n'ajoutiez réellement l'autorisation view au modèle, donc elle rompt à nouveau la compatibilité descendante. Au moins, cela nécessite un changement de code - nous rompons donc la compatibilité ascendante _et_ forçons les utilisateurs à retravailler leur base de code.

Bien sûr, le remplacement est toujours une option pour répondre à ses besoins spécifiques, mais je pense que l'idée générale de tastypie est de fournir des valeurs par défaut raisonnables et sûres qui ne nécessitent pas l'ajout de code personnalisé ...

En bref, je pense que ce changement devrait être annulé pour une meilleure mise en œuvre.

La permission change vient de Django lui-même. C'est la valeur par défaut de Django, c'est ainsi que l'application Django Admin est configurée. L'option view ne l'est pas. J'ai personnellement nommé le mien read .

Vous ne savez pas ce que vous voulez dire en vérifiant le model . Si vous voulez vérifier le _meta, il se peut qu'il soit incomplet. Si vous voulez dire frapper la base de données, je l'ai trouvé inutilement cher.

À ma préférence, ce que vous proposez semble être du côté «trop de magie» pour une autorisation par défaut. Le simple fait d'avoir une valeur par défaut sûre, facilement remplaçable, semble être suffisant. Mais c'est juste mon opinion.

Le changement a été documenté ici: https://github.com/django-tastypie/django-tastypie/blob/master/docs/release_notes/v0.13.2.rst

Franchement, je ne vois pas comment l'autorisation de modification pour les actions de lecture augmente la sécurité car en même temps cette autorisation permet également PUT. Le mélange des autorisations pour différentes actions ne semble pas un bon choix.

Nous savons que si un utilisateur peut changer quelque chose, alors il peut le lire, c'est ainsi que l'administrateur Django fait les choses.

Cette version est plus sécurisée, car elle oblige le développeur à réfléchir à ce qu'il fait. Si au lieu d'inventer leur propre autorisation de «lecture», le développeur choisit de donner délibérément à chacun des autorisations de «modification» alors qu'il ne devrait avoir que des autorisations de «lecture», c'est son problème; Je ne peux pas empêcher les autres développeurs de faire délibérément des choses stupides, je suis ici pour empêcher Tastypie de faire des choses stupides. Le but de ce changement était d'empêcher les autorisations de lecture globales sur toute ressource utilisant DjangoAuthorization, ce à quoi les développeurs pourraient ne pas s'attendre; le nouveau comportement est conforme à l'expérience des développeurs dans l'admin Django.

Si vous voulez l'ancien comportement:

  1. Ne passez pas à la version 0.13.2.
  2. Ou remplacez les méthodes read_list and read_detail`.

Si vous pensez que la documentation pourrait être améliorée, n'hésitez pas à soumettre un PR.

appréciez vos commentaires. merci pour le lien vers la documentation, assez juste, mon dommage d'avoir manqué cela (veuillez noter que le problème est attribué à la v0.13.4 alors que les documents sont en v0.13.2).

Permettez-moi de faire quelques remarques finales de mon point de vue:

Nous savons que si un utilisateur peut changer quelque chose, alors il peut le lire, c'est ainsi que l'administrateur Django fait les choses.

L'administrateur de Django utilise l'autorisation change car l'interface d'administration _est_ sur les objets _changeant_. Cela a du sens là-bas. La requête GET sur une API REST par définition concerne la _reading / visualisation_. Je pense que la plupart des développeurs ne s'attendent tout simplement pas à ce que DjangoAuthorization refuse la lecture en raison d'une autorisation de changement manquante.

Cette version est plus sécurisée, car elle oblige le développeur à réfléchir à ce qu'il fait.

L' un des tastypie annoncés de caractéristiques est de fournir defaults_ _reasonable. Ne serait-il pas tout à fait raisonnable de supposer que les méthodes GET (par définition: lecture) et PUT (modification) d'une API, étant des opérations différentes dans toutes leurs intentions et objectifs, nécessitent également des autorisations différentes?

Je serai heureux de contribuer à un PR dans le sens de ce que j'ai écrit si vous pensez que c'est un ajout précieux.

L'autorisation de modification vient de Django lui-même. (...) La vue des options ne l'est pas.

il y a un PR en attente dans Django pour ajouter un view permission c'est pourquoi j'ai utilisé view.

Nous n'allons pas autoriser les opérations de lecture publiques / globales par défaut. C'est définitif. Et nous n'allons pas essayer de deviner comment les développeurs ont leurs autorisations configurées alors qu'il n'existe actuellement aucun moyen standard de le faire. Nous ne savons même pas s'il faut l'appeler "lecture" ou "vue", et je ne veux pas qu'un groupe de personnes vienne ici en disant "je le fais comme ça" ou "la nouvelle version de Django l'appelle autre chose" .

Si et quand Django prend en charge une autorisation de lecture / vue prête à l'emploi, nous passerons à cela. Pour l'instant, les développeurs devront simplement écrire du code personnalisé pour gérer la manière personnalisée dont ils gèrent les autorisations.

Je sais que ce problème est clos, mais je veux juste intervenir et dire que ce changement m'a essentiellement empêché de migrer un projet existant vers 0.13.x.

@miraculixx Je pense que vous avez tout à fait raison en ce qui concerne le fait

Lorsque vous apportez des modifications de rupture de production, pouvez-vous au moins refléter cela dans la gestion des versions?
La gestion des versions x.y.z Tastypie ressemble beaucoup à ce que la plupart des gens attendent , c'est-à-dire généralement:

Étant donné un numéro de version MAJOR.MINOR.PATCH, incrémentez:
..
Version PATCH lorsque vous effectuez des corrections de bogues rétrocompatibles.

Je viens de passer une heure très inconfortable à retracer cela lors d'un nouveau déploiement de production.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

hashemian picture hashemian  ·  6Commentaires

bmihelac picture bmihelac  ·  40Commentaires

adamzap picture adamzap  ·  18Commentaires

bastbnl picture bastbnl  ·  10Commentaires

lordi picture lordi  ·  6Commentaires