Django-tastypie: Precisa de um padrão muito mais seguro: `DjangoAuthorization` não deve permitir acesso` read` a todos os objetos do modelo

Criado em 6 jan. 2016  ·  10Comentários  ·  Fonte: django-tastypie/django-tastypie

Olhando para tastypie/authorization.py (em torno de 133 - branch master em 04/01/2016), o padrão, tanto read_list quanto read_details bypass user.has_perm() check, o que é bastante inseguro e é um padrão ruim.

O padrão Admin do Django não é convencional. Então, eu pude ver como isso foi mal interpretado.

https://docs.djangoproject.com/es/1.9/topics/auth/default/#permissions -and-autorização

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.

Essencialmente, "change_xyz" é o código de permissão para "ler" e "atualizar". Acho que o melhor padrão seria seguir o Admin do 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

Comentários muito úteis

Quando você faz alterações que interrompem a produção, você pode pelo menos refletir isso no controle de versão?
A versão de x.y.z Tastypie se parece muito com o que a maioria das pessoas espera , ou seja:

Dado um número de versão MAJOR.MINOR.PATCH, incremente:
..
Versão PATCH quando você faz correções de bug compatíveis com versões anteriores.

Acabei de passar uma hora muito desconfortável rastreando isso durante uma nova implantação de produção.

Todos 10 comentários

Compreendo que isso já foi mesclado, mas ainda tenho problemas com isso. Antes de abrir uma nova solicitação, aqui está minha preocupação:

Esta mudança infelizmente quebra o código existente e, portanto, é incompatível com versões anteriores (anteriormente, todas as solicitações GET passariam pelo DjangoAuthorization). Para consertar o código de alguém, as duas únicas opções são dar a todos os usuários permissão de 'mudança' (ruim) ou criar uma subclasse de DjangoAuthorization para uma implementação customizada das ações de leitura (potencialmente muito trabalho). Isso foi intencional?

Agradeço o raciocínio por trás disso no contexto de administração django, mas duvido que definir 'read' como o equivalente a 'change' em um contexto de API seja uma suposição padrão sensata, pois não é o comportamento esperado. Afinal, se GET é um método permitido junto com DjangoAuthorization, por que ele recusaria o acesso com base no fato de que o usuário não tem a permissão change ?

Proponho a seguinte implementação alternativa:

_para ler_detalhes_

  • se o modelo tem uma permissão view , verifique isso (= melhoria para quem precisa)
  • se não houver permissão view , sempre permita (= compatível com versões anteriores)

_para read_list_

  • se o modelo tem uma permissão list , verifique isso (= melhoria para quem precisa)
  • se não houver permissão list , sempre permita (= compatível com versões anteriores)

Desta forma, tastypie adiciona um padrão que é compatível com os padrões de permissão do Django enquanto fornece um caminho fácil para melhorar adicionando permissões de visualização e lista para aqueles que precisam, sem escrever uma implementação customizada do DjangoAuthorization.

Deve haver pelo menos uma maneira de especificar a permissão padrão:

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 será quem decidirá.

Apenas minha opinião aqui, acho que foi um problema de segurança permitir a leitura por padrão. Eu não esperava por isso, até que estava bem perto da produção. Acho que quebrar a compatibilidade com versões anteriores é necessário neste contexto.

Parece que sua sugestão requer a alteração do passe de parâmetros para DjangoAuthorization para o seu código existente, nesse caso, pensarei que é mais claro chamar a classe de outra coisa.

Considere, read_permission='view' caso, aqui pode ser exatamente o que você precisa. Não vejo por que é menos ideal do que

class ModifiedDjangoAuthorization(DjangoAuthorization):
    READ_PERM_CODE = 'view'

Se você quiser alterar outro, basta substituir os métodos. A mudança foi projetada para tornar muito mais fácil fazer isso.

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)

A mudança levou em consideração a modificação e a tornou mais fácil. Eu não acho que deveria ser feito como parâmetros de inicialização.

Acho que foi um problema de segurança permitir a leitura por padrão.

Não estou questionando a intenção do problema original. Apenas apontando que a implementação como mesclada está quebrando o código e as suposições existentes das pessoas sem dizer isso e sem nenhuma opção eficiente de reversão.

Parece que sua sugestão requer a alteração de parâmetros de passagem para DjangoAuthorization para seu código existente,

Se você olhar minha solução proposta novamente, o que estou defendendo é dar às pessoas opções com um padrão seguro e compatível com versões anteriores. Nenhuma mudança seria necessária no código do usuário neste caso.

Acho que quebrar a compatibilidade com versões anteriores é necessário neste contexto.

Discordo. A mudança, como atualmente mesclada, não apenas quebra a compatibilidade com versões anteriores, mas também introduz um problema de segurança potencial muito maior, pois a maneira óbvia (implícita pela implementação atual) é atribuir a permissão de mudança a todos os usuários que deveriam ter permissão para GET.

Francamente, não consigo ver como a permissão change para ações de leitura aumenta a segurança, pois ao mesmo tempo essa permissão também permite PUT. Misturar permissões para ações diferentes não parece uma boa escolha.

Infelizmente, sua proposta de ModifiedDjangoAuthorization não funcionará a menos que você realmente adicione a permissão view ao modelo, portanto, está novamente quebrando a compatibilidade com versões anteriores. Pelo menos isso requer mudança de código - então nós quebramos a compatibilidade com versões anteriores _e_ forçamos os usuários a refazer sua base de código.

É claro que substituir é sempre uma opção para atingir os requisitos específicos de alguém, no entanto, acho que a ideia geral no tastypie é fornecer padrões sensíveis e seguros que não requerem a adição de código personalizado ...

Resumindo eu acho que essa mudança deveria ser revertida para uma melhor implementação.

A permissão change vem do próprio Django. É o padrão do Django, é como o aplicativo Django Admin é configurado. A opção view não é. Eu pessoalmente chamei o meu de read .

Não tenho certeza do que você quer dizer com verificar model . Se você quer dizer verificar o _meta, então ele pode estar incompleto. Se você quer dizer acertar o banco de dados, achei desnecessário caro.

Para minha preferência, o que você propôs parece estar do lado "muito mágico" para uma autorização padrão. Apenas ter um padrão seguro, facilmente substituível, parece ser o suficiente. Mas, essa é apenas minha opinião.

A mudança foi documentada aqui: https://github.com/django-tastypie/django-tastypie/blob/master/docs/release_notes/v0.13.2.rst

Francamente, não consigo ver como a permissão de alteração para ações de leitura aumenta a segurança, pois ao mesmo tempo essa permissão também permite PUT. Misturar permissões para ações diferentes não parece uma boa escolha.

Sabemos que se um usuário pode mudar algo, então ele pode ler, é assim que o administrador do Django faz as coisas.

Esta versão é mais segura, pois força o desenvolvedor a pensar no que está fazendo. Se, em vez de inventar sua própria permissão de "leitura", o desenvolvedor escolher deliberadamente dar a todos as permissões de "mudança", quando deveriam ter apenas permissões de "leitura", esse é o problema; Não posso impedir que outros desenvolvedores façam coisas estúpidas deliberadamente, estou aqui para impedir que Tastypie faça coisas estúpidas. O objetivo dessa mudança era evitar permissões globais de leitura em qualquer recurso que usasse DjangoAuthorization, o que os desenvolvedores podem não esperar; o novo comportamento está de acordo com a experiência dos desenvolvedores no administrador do Django.

Se você quiser o comportamento antigo:

  1. Não atualize para 0.13.2.
  2. Ou substitua os métodos read_list and read_detail`.

Se você acha que a documentação pode ser melhorada, sinta-se à vontade para enviar um PR.

aprecio seu feedback. obrigado pelo link para o documento, justo, minha má por perdê-lo (observe que o problema está atribuído à v0.13.4 enquanto os documentos estão na v0.13.2).

Deixe-me fazer algumas observações finais do meu pov:

Sabemos que se um usuário pode mudar algo, então ele pode ler, é assim que o administrador do Django faz as coisas.

O administrador do Django usa a permissão change porque a interface do administrador _é_ sobre _changing_ objetos. Faz sentido aí. A solicitação GET em uma API REST, por definição, é sobre _reading / visualização_. Eu acho que a maioria dos desenvolvedores simplesmente não espera que o DjangoAuthorization recuse a leitura com base na falta de permissão para alterar.

Esta versão é mais segura, pois força o desenvolvedor a pensar no que está fazendo.

Um dos recursos anunciados do tastypie é fornecer _padrão razoável_. Não seria bastante razoável supor que os métodos GET (por definição: ler) e PUT (alterar) de uma API, sendo operações diferentes em todas as intenções e propósitos, também requerem permissões diferentes?

Ficarei feliz em contribuir com um RP nos moldes do que escrevi, se vocês acharem que é uma adição valiosa.

A permissão de mudança vem do próprio Django. (...) A visualização de opções não é.

há um PR pendente no Django para adicionar um view permission que é o motivo pelo qual usei o view.

Não vamos permitir operações de leitura pública / global por padrão. Isso é definitivo. E não vamos tentar adivinhar como os desenvolvedores têm suas permissões configuradas quando não existe atualmente uma maneira padrão de fazer isso. Não temos certeza se devemos chamar de "ler" ou "visualizar", e não quero um monte de gente vindo aqui dizendo "Eu faço assim" ou "o novo lançamento do Django chama de outra coisa" .

Se e quando o Django suportar uma permissão de leitura / visualização pronta, nós mudaremos para isso. Por enquanto, os desenvolvedores apenas terão que escrever algum código personalizado para lidar com a maneira personalizada como lidam com as permissões.

Eu sei que este problema está resolvido, mas eu só quero intervir e dizer que essa mudança basicamente me bloqueou de migrar um projeto existente para 0.13.x.

@miraculixx Acho que você está totalmente correto com relação ao fato de que exigir permissões de alteração simplesmente para visualizar dados é um pouco louco. Acho que podemos culpar Django por, de alguma forma, ainda, não ter o conceito de uma permissão de visualização (o que explode a minha em um outro nível, acho que é uma loucura que um projeto incluindo um componente administrativo CRUD simplesmente não tenha uma permissão para a parte READ do CRUD).

Quando você faz alterações que interrompem a produção, você pode pelo menos refletir isso no controle de versão?
A versão de x.y.z Tastypie se parece muito com o que a maioria das pessoas espera , ou seja:

Dado um número de versão MAJOR.MINOR.PATCH, incremente:
..
Versão PATCH quando você faz correções de bug compatíveis com versões anteriores.

Acabei de passar uma hora muito desconfortável rastreando isso durante uma nova implantação de produção.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

bastbnl picture bastbnl  ·  10Comentários

adamzap picture adamzap  ·  18Comentários

hashemian picture hashemian  ·  6Comentários

bmihelac picture bmihelac  ·  40Comentários

Roarster picture Roarster  ·  8Comentários