Hi all, I need to ask for a Technical Board decision on the resolution of Ticket #31747.
Ticket #31747: Avoid potential admin model enumeration https://code.djangoproject.com/ticket/31747 PR #13134: Fixed #31747 -- Fixed model enumeration via admin URLs. https://github.com/django/django/pull/13134 ## Summary The initial issue is that there is a difference in HTTP response code for admin URLs depending on whether a URL routes to an existing model or not: http://127.0.0.1:8000/admin/auth/user/ -> 302 to login http://127.0.0.1:8000/admin/auth/group/ -> 302 to login http://127.0.0.1:8000/admin/auth/foo/ -> 404 In principle an attacker could use this to leak information about the app's models, which could be part of a further attack. This was originally reported to the Django Security Team, who declined to take it as a security issue, but recommended adding a final catch-all view to the admin, which would redirect all unauthenticated requests to login, thus masking the private model info. Jon Dufresne picked this issue up, and submitted a PR, but in so-doing noticed that a very similar (the same?) issue occurred with APPEND_SLASH behaviour in the admin too. (Try URLs without the slash, looking for a redirect to the correct URL **before** being redirected to login.) The initial thought was that we might need to remove APPEND_SLASH URL normalisation for the admin. We were able to avoid that by restricting the append_slash-style URL normalisation for the admin to authenticated staff users. This addresses the main force of the original report (which is unauthenticated users remotely probing the site) but Jon noted that it still allows a staff-user to potentially discover the existence of model for which they don't have permissions in this way. In order to avoid this last threat Jon felt that we still needed to disable append slash URL normalisation for the admin. In contrast, I felt the threat of a staff user discovering models in this way would apply to only a tiny fraction of all installations, and that the utility of URL normalisation vastly outweighs that on balance. We have a trade-off between balancing privacy and usability here. After much discussion and thought, Jon and I came to agree (I think 🙂) that an `AdminSite.append_slash` toggle was needed to control the behaviour here. If privacy is paramount, you can set that to `False` to disable the URL normalisation in the admin. If you don't need to keep models secret from staff users you can have it `True` and still get the benefits of append slash behaviour. We felt this was something that everyone could live with. Wherever you are on the spectrum, for the simplest case, where you're just using the default admin site, you toggle the behaviour with a single line in your URL conf: from django.contrib import admin admin.site.append_slash = ...set True/False as you want here... (On the way, we also found a way of opting-out for a single ModelAdmin, but let's not talk about that here.) All good, except... ## Decision needed Jon and I still don't agree on the correct default value for `AdminSite.append_slash`. Our disagreement is a difference in weighting, which is hard to argue about, and we don't want to fall out over it either. So we'd like to ask the Technical Board to decide. ### Option 1 - default `True` As the PR stands: https://github.com/django/django/pull/13134 * `AdminSite.append_slash` defaults to `True`. * This is consistent with the past behaviour for authenticated staff users. ### Option 2 - default `False` * Make `AdminSite.append_slash` defaults to `False`. * This would be a breaking change, but... * We could document it in the release notes, and... * The "fix" is the simple adjustment in the URL conf for most folks. ### Option 3 - default `False` with deprecation * We could do 2, but somehow with a deprecation period. I don't think we should do this. It's difficult and a hard break at the end of the deprecation, but I mention it for completeness (and because the PR originally included a deprecation of the APPEND_SLASH behaviour for the admin.) My opinion is that we should opt for Option 1, as consistent with the past behaviour, and most appropriate for most users. I can live with Option 2 if that's the decision, but I think we'd artificially elevating an issue that simply doesn't apply to most installs. I think Jon's opinion is the counterpart of that. He prefers Option 2, as the more secure default. He could live with Option 1 if that's the decision, but thinks we shouldn't be asking opt-in to privacy here, whatever the usability consequences. As such, can we ask the TB to choose an option? Thanks. Jon: hopefully I'e presented your view fairly; if you feel not, please do follow-up 🙂 Kind Regards, Carlton Hi all, I need to ask for a Technical Board decision on the resolution of Ticket #31747. Ticket #31747: Avoid potential admin model enumeration https://code.djangoproject.com/ticket/31747 PR #13134: Fixed #31747 -- Fixed model enumeration via admin URLs. https://github.com/django/django/pull/13134 ## Summary The initial issue is that there is a difference in HTTP response code for admin URLs depending on whether a URL routes to an existing model or not: http://127.0.0.1:8000/admin/auth/user/ -> 302 to login http://127.0.0.1:8000/admin/auth/group/ -> 302 to login http://127.0.0.1:8000/admin/auth/foo/ -> 404 In principle an attacker could use this to leak information about the app's models, which could be part of a further attack. This was originally reported to the Django Security Team, who declined to take it as a security issue, but recommended adding a final catch-all view to the admin, which would redirect all unauthenticated requests to login, thus masking the private model info. Jon Dufresne picked this issue up, and submitted a PR, but in so-doing noticed that a very similar (the same?) issue occurred with APPEND_SLASH behaviour in the admin too. (Try URLs without the slash, looking for a redirect to the correct URL **before** being redirected to login.) The initial thought was that we might need to remove APPEND_SLASH URL normalisation for the admin. We were able to avoid that by restricting the append_slash-style URL normalisation for the admin to authenticated staff users. This addresses the main force of the original report (which is unauthenticated users remotely probing the site) but Jon noted that it still allows a staff-user to potentially discover the existence of model for which they don't have permissions in this way. In order to avoid this last threat Jon felt that we still needed to disable append slash URL normalisation for the admin. In contrast, I felt the threat of a staff user discovering models in this way would apply to only a tiny fraction of all installations, and that the utility of URL normalisation vastly outweighs that on balance. We have a trade-off between balancing privacy and usability here. After much discussion and thought, Jon and I came to agree (I think 🙂) that an `AdminSite.append_slash` toggle was needed to control the behaviour here. If privacy is paramount, you can set that to `False` to disable the URL normalisation in the admin. If you don't need to keep models secret from staff users you can have it `True` and still get the benefits of append slash behaviour. We felt this was something that everyone could live with. Wherever you are on the spectrum, for the simplest case, where you're just using the default admin site, you toggle the behaviour with a single line in your URL conf: from django.contrib import admin admin.site.append_slash = ...set True/False as you want here... (On the way, we also found a way of opting-out for a single ModelAdmin, but let's not talk about that here.) All good, except... ## Decision needed Jon and I still don't agree on the correct default value for `AdminSite.append_slash`. Our disagreement is a difference in weighting, which is hard to argue about, and we don't want to fall out over it either. So we'd like to ask the Technical Board to decide. ### Option 1 - default `True` As the PR stands: https://github.com/django/django/pull/13134 * `AdminSite.append_slash` defaults to `True`. * This is consistent with the past behaviour for authenticated staff users. ### Option 2 - default `False` * Make `AdminSite.append_slash` defaults to `False`. * This would be a breaking change, but... * We could document it in the release notes, and... * The "fix" is the simple adjustment in the URL conf for most folks. ### Option 3 - default `False` with deprecation * We could do 2, but somehow with a deprecation period. I don't think we should do this. It's difficult and a hard break at the end of the deprecation, but I mention it for completeness (and because the PR originally included a deprecation of the APPEND_SLASH behaviour for the admin.) My opinion is that we should opt for Option 1, as consistent with the past behaviour, and most appropriate for most users. I can live with Option 2 if that's the decision, but I think we'd artificially elevating an issue that simply doesn't apply to most installs. I think Jon's opinion is the counterpart of that. He prefers Option 2, as the more secure default. He could live with Option 1 if that's the decision, but thinks we shouldn't be asking opt-in to privacy here, whatever the usability consequences. As such, can we ask the TB to choose an option? Thanks. Jon: hopefully I'e presented your view fairly; if you feel not, please do follow-up 🙂 Kind Regards, Carlton -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/384107bd-511a-410e-8acb-e4a1f76b303cn%40googlegroups.com.