1. 7
  1.  

    1. 13

      I have read through all the linked tickets and agree with the wontfix resolution in every case.

      For me, this basically boils down to “if you do the wrong thing, bad things happen”. All of these proposed “security hardenings” only apply if you already made a mistake, like turning on DEBUG in production. I’d rather not have the settings displayed in the debug page filtered for cases where people used it in a wrong situation but instead have everything displayed when using it in the right way. Similarly, I’d rather have caching be as fast as possible when used the right way instead of slowing it down just in case somebody uses it the wrong way.

      A framework like Django can never completely protect you from making mistakes that might compromise the security of your application and I think the developers’ decisions on where to draw that line and why was reasonable in all cases mentioned in this article.

      1. 9

        I can’t agree here; I think that it’s important – more so for frameworks, in fact! – to make it actively difficult to do dangerous things in production.

        Speed is less important than the security of your users’ data and the safety of visitors to your site. You can identify performance gaps after you’ve shipped, but if you ship with an exploitable security defect, you generally won’t find out about that until the damage is already done.

        1. 3

          Performance is only an issue with the suggestion about pickle. A scenario where an attacker can somehow inject arbitrary data to be later unpickled into the cache is not possible through use of the Django cache API since if you use that, only an object to be pickled can be supplied, not the bytes that are later unpickled.

          The case the article makes is that signing the data in the cache would provide some measure of safety if the cache backend and its authentication data are mistakenly exposed to the internet. So if you already made two huge mistakes in your setup, this would prevent some of the fallout.

          So while I agree that generally, security and integrity of a system is certainly more important than its performance, I don’t agree that this should extend to scenarios which are not possible when using the system in any reasonable manner.

          1. 4

            If it is possible to use a system in a manner, it’s reasonable to expect that someone will. Coupled with Python’s flexibility – especially about truthiness – there are a lot of footguns here.

            I can see from your comments that you’re not going to be persuaded, so I’m not really writing this to you, so much as “writing it so that others who read this thread don’t think that anti-developer attitudes like yours are universal”

            There are developers, even in F/OSS, who want to deliver safe by default, difficult to misuse tools.

            1. 8

              I feel like “if it is possible to use a system in a manner, it’s reasonable to expect that someone will” is both true and quite misleading. Should Django really protect you from misconfiguration of the system it runs on? Because that’s what we are talking about in the pickle case. Should it then also protect against you accidentally opening the database to the Internet with write access enabled? Or running an outdated kernel with security issues?

              Also, you’re jumping between points, which makes it difficult to engage. First, you talked about performance and thus the point the article makes about pickle. Instead of further engaging on this topic, you then jumped to truthiness, which is presumably referring to the point the article makes about preventing a the mistake of setting DEBUG to something like “off”. I think this is the most reasonable suggestion the article makes although it is something already caught by following the clear suggestion made in the documentation about running manage.py check –deploy before deploying. I also think the point the Django developers make in the issue about this additional check only making sense as part of a broader effort was quite reasonable.

              I think Jackevansevo put it well when they said,

              I’m sympathetic, but on the other hand as developers we’re all responsible to do a little due diligence.

          2. [Comment removed by author]

          3. 8

            All of these proposed “security hardenings” only apply if you already made a mistake, like turning on DEBUG in production.

            Right but DEBUG="false" turns DEBUG mode on, which feels crazy and like it would literally never be expected behavior and absolutely should be patched. A misguided user could be explicitly trying to ensure they’re safe and end up with a vulnerability. This is a ridiculous footgun to not patch.

            1. 2

              I mean, it falls out naturally from any non-empty string being truthy. bool("false") -> True

              The framework could check that isinstance(DEBUG, bool) and barf, and that would be safe but not idiomatic. The real mistake is configuring your application with environment variables rather than in the config file and then forgetting that environment variables are strings. I actually agree that the framework should go out of its way to only accept bools as values for DEBUG, but the user has to go against the grain in two different ways to cause this problem.

              1. 4

                from any non-empty string being truthy. bool(“false”) -> True

                Right, and that’s a terrible behavior in general but, okay, that’s Python. But it should be handled more strictly (or more carefully) for something security sensitive. Debug="False" should never be interpreted as Debug=True, I think that’s really straightforwardly justified.

                1. 1

                  I think it’s fairly common to use environment variables to configure an application. In fact, if I understand the example from django-environ correctly, they advise you to use the bool constructor as a “cast” for booleans from environment variables. IIUC, this doesn’t even work…

                  1. 1

                    Those examples don’t necessarily use the bool constructor directly; environ might be applying some cleverness (and I’m assuming the presence of a method called environ.Env.bool means it is).

              2. 6

                So I don’t have an extensive Python background, but I got hired into a Python dev shop a few years ago. I find this comment fascinating because it is so similar to the thinking of my Pythonista coworkers. I have learned to respect this way of thinking, however I never saw it before I got into Python development.

                In Python culture the attitude is very often, “we give people sharp tools, and they need to know how to use the tools well. If they hurt themselves, it’s their fault – we can’t protect users from themselves, so why try?” [^1]

                In some other developer subcultures it’s a bit different. The attitude is more often, “make it safe first, then allow users to tweak some knobs to make it practical.”

                Both ways of thinking have merit. But from a security perspective, you have to acknowledge that users are human and will make mistakes. No, you can’t protect users from themselves completely, but you CAN make it easier for fallible humans to fall into the pit of success.

                [^1]: For what it’s worth I’m not meaning to imply Django is unsafe by default. But the author has encountered a real-world situation that has probably happened to a lot of people, so Django might be able to improve here.

                1. 5

                  In Python culture the attitude is very often, “we give people sharp tools, and they need to know how to use the tools well. If they hurt themselves, it’s their fault – we can’t protect users from themselves, so why try?”

                  This sounds more like C++ not the Python I know.

                  1. 2

                    I’m only occasionally a Python developer, but this attitude seems quite normal to me. I’m curious what subcultures you’ve encountered that prioritize safety? And, do you think they do it in a way that doesn’t compromise the usefulness of the language?

                    I guess my feeling is that if you prevent people from doing dumb things, you most often prevent them from doing clever things, too

                    1. 2

                      C# is the subculture I have most experience with. It’s not a universal thing, more of a generalization.

                      Without going too far down a rabbit hole, the best APIs aren’t the ones that “prevent” you from doing dumb things. Instead, they make correct usage feel like the easiest most natural way to do things.

                  2. 4

                    So you’re not on board with “secure by default” and then we can only agree to disagree, that’s fair.

                    1. 12

                      I feel that’s an unfair assessment of what I wrote.

                      What I don’t agree with is your definition of what “secure by default” entails. If you follow the documentation and reasonable best practices (like running manage.py check –deploy as the sibling comment mentions), then none of the issues you mention are a problem. You seem to want to protect from using the framework in a way it’s not supposed to be used and that’s nothing Django can do completely. When developing a Django app, you are writing code, and Django will never be able to completely protect you from writing insecure code without vastly changing its scope, which is one of the things the developers told you when closing your tickets.

                      1. 6

                        Isn’t DEBUG initially False? Is that not “secure by default”?

                        1. 3

                          There are a lot of sites that use, say, environment variables to configure settings. Environment variables are strings. All strings of non-zero length are “truthy”

                          Secure by default is absolutely a core value to have, and you’re right, the default is good, but it’s also useful to include securing the expected user behaviour after that initial construction. Guardrails are good things, and enable developers to work faster and more safely.

                    2. 12

                      I feel like Django would have warned against this (maybe I’m missing nuance): https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/#run-manage-py-check-deploy

                      If they’d just run: manage.py check --deploy

                      Which should be caught by https://docs.djangoproject.com/en/5.1/ref/checks/#security

                      security.W018: You should not have DEBUG set to True in deployment.
                      
                      1. 2

                        Many users of Django either do not know this feature when they are starting out and only learn about it later or forget to run these checks after making changes. They are easy to miss.

                        1. 12

                          Many users of Django either do not know this feature when they are starting out

                          It’s recommended as the very first thing you do on the official ‘How to Deploy Django Guide’ https://docs.djangoproject.com/en/5.1/howto/deployment/#how-to-deploy-django which is the top result I get when googling ‘Django deployment’

                          Finally, before you deploy your application to production, you should run through our deployment checklist to ensure that your configurations are suitable.

                          I’m sympathetic, but on the other hand as developers we’re all responsible to do a little due diligence.

                          1. 4

                            Its also referenced in settings.py on freshly created projects. Plenty of opportunities to stumble upon it.

                      2. 8

                        On one hand “secure by default” can end in the same place as “won’t someone please think of the children!”. Which is to say it never ends and is used as a justification for increasingly questionable restraints. In some cases trying to protect users from “mistakes” just makes things worse. See mysql_escape_string, mysql_real_escape_string, and PHP in general for an example of bad historically bad defaults and bad fixes for bad defaults.

                        OTOH, I consider some of the issues raised pretty relevant. Here’s my take, if you don’t agree you can have your money back.

                        1. Exposing a database to the public internet is a level of dumbness that I honestly don’t think is worth trying to recover from in the django framework. “What if attackers can arbitrarily edit our data?” I think it was Raymond Chen who characterizes these issues as “rather requires being on the wrong side of the airlock”.
                        2. settings.DEBUG should be a bool and only a bool. I’m an unrepentant fan of strong types (ok python people, strong static types) just about anywhere I can in order to avoid stuff like settings.DEBUG = "False" turning DEBUG on.
                        3. Pickle: Around the time django was built, using native serialization for session data was common. For java, perl, etc. But in 2024 I think running eval() on stuff in your database (or redis cache) by default is a crap default. Arbitrary object deserialization is just a gift to hackers that keeps on giving. In case anyone isn’t aware: Pickle essentially allows you to run arbitrary code. But also in 2024 signing data by default is not a terrible idea, in the same way that mTLS makes sense even within the datacenter.
                        1. 8

                          Please read the section about self-promotion on https://lobste.rs/about

                          1. 4

                            The post is to educate, gets me no money, has no ads, is not related to my employer and not endorsing any products. I did check the box that I am the author. If you want to keep me as a member, please be more welcoming to me. Thank you.

                            1. 17

                              Self-promotion: It’s great to have authors participate in the community, but not to exploit it as a write-only tool for product announcements or driving traffic to their work. As a rule of thumb, self-promo should be less than a quarter of one’s stories and comments.

                              This rule applies to everyone, even if you’re not making money off the posts.

                              1. 13

                                The rule is enforced so inconsistently. Posts with more contention get the rulebook thrown at them, while people like https://lobste.rs/~stapelberg/ or even myself get away with it.

                                1. 3

                                  You participate quite a bit outside of your own submissions though, unlike OP who has apparently never commented on something they didn’t write.

                                  1. 4

                                    As someone that feels discouraged to submit my own work because of this rule, I don’t find this argument to be compelling. What I get from this is, “as long as you contribute to the community in other ways, you can totally break these rules anytime you want, within reason, I guess.” That seems a bit silly to me.

                                    Edit: grammar

                                    1. 10

                                      Yours is an incorrect reading, and you haven’t submitted anything since you joined of any variety.

                                      It’s not “you can break these rules anytime you want, within reason” so much as “the rule is not to post the vast majority of time your own stuff”. Any reasonable amount of other interaction means you are following that custom. It’s not some big thing, as much as occasional folks kvetch about it.

                                      That custom exists for a reason: people see Lobsters as a marketing or advertising channel and treat it that way. It has been abused in the past. It appears to be being abused in the present. It will doubtless be abused in the future. That custom and vigorous flagging–when people notice!–are one of the few things we have going for us.

                                      You’re new (5 months according to your profile at time of writing), so maybe you haven’t seen this before and it all seems rather arbitrary–so, I’ll try and explain:

                                      Lobsters is a slow-moving site (compared to, say, the orange site or a decently popular subreddit). Posts here stay on the frontpage for a day or two easily. In advertising terms, a slot here stays up for a while and gets a lot of impressions by a pretty well-defined (and valuable!) audience. I have heard valuations in the low 5 figures. This makes us a target for growth hackers (and the modlog is full of efforts to kick them out when they are discovered).

                                      We could ban self-promotion altogether, but it turns out that sometimes people do write interesting things themselves and would like to share them. We could always allow self-promotion, but that is basically incompatible with trying to prevent growth-hacking and marketing.

                                      So, instead, we make the compromise of “If you post here and mostly bring in other interesting things, and occasionally your own stuff, that’s probably okay”. This means that anybody who actually is in it just to shill their own work must also do what amounts to community service, and that tends to give an easy way of spotting growth hackers and free riders.

                                      1. 5

                                        I think it’s weird that you point out that I comment, but haven’t submitted anything, as if that has any impact on my argument here. Likewise, having a newer account doesn’t bar me from having an opinion or disagreeing with someone else. I’m clearly not some free loading self promoter. I’m a real person that just happens to disagree with that comment.

                                        I’m not disagreeing with the custom. The notion that it’s not always applied fairly does resonate with me, though.

                                      2. 5

                                        The rule is not “only 25% of your submissions can be your own”, its “25% of stories and comments”, so what you call “other ways” is explicitly part of it. But yes, I’m arguing that there is a fundamental difference between “doesn’t participate at all outside own submissions” (which is explicitly called out as what the rule wants to prevent) and “does participate regularly, but maybe doesn’t meet the rule of thumb threshold”.

                                    2. 3

                                      Agree. I think these warnings are something that could and should be automated instead of people haphazardly being chastised. Most guidelines aren’t easy to automate, but this one would be. (And I definitely think it’s a good rule!)

                                      If an exception is made for some people who only come here to post releases/links that a lot of people are interested in (lobste.rs/~aphyr comes to mind), then that can be explicitly flagged instead of them being unofficial royalty.

                                  2. 10

                                    Hi. I’m fine losing you as a member if you only comment on your own stuff and (with one exception) only post your own writing. We’ve lost longer and more engaged contributors over less.

                                    “Friendlysock, this isn’t terribly friendly at all!”–okay, sure, but you’re engaged in behavior that is indistinguishable from a long list of bad-faith and near-bad-faith actors. I’m sure lots of them have similar sob stories if given the opportunity.

                                    In order to avoid this, for what it’s worth, all you have to do is comment a few times in other stories, submit interesting learnings that you didn’t write, and not be a shithead. It isn’t a particularly high bar, and if you find it difficult to clear there are many other communities that you’d doubtless find more welcoming.

                                    1. 8

                                      The idea is to discourage folks who are here only to submit their own work, and only to participate in comments on their own stories — it’s a community, not a publication channel. This behaviour is unwelcome.

                                  3. 3

                                    The Django project recently removed the ability to serialize session data using pickle, for security reasons, without updating the default JSON serializer to support common Python datatypes (most notably datetime). It was absolutely the right thing to do, but it hit me as an unexpected flag day when updating a hobby app to Django 5.0. I am absolutely gobsmacked to hear that they didn’t stop using pickle in the cache framework at the same time. They warn about it in the docs, but only for file-backed caches, not for the other backends that use it.

                                    1. 3

                                      I probably don’t think they need to sign the hash objects, but I’m also convinced that it’s trivial and extremely unlikely to impact performance. blake3(object, secret) is not going to be the bottleneck but yeah sure let it be disabled, maybe enable by default.

                                      The fact that DEBUG="false" means DEBUG is enabled and they won’t fix it, inexcusable to me and I’ll literally never touch Django because of it. I was not compelled by their reasoning here at all. “Users would expect us to implement this handling elsewhere” - who cares? Also, just make it an error - no need to parse “no”, just literally reject anything else that isn’t a bool. No one is setting DEBUG="false" and thinking that it means true, and if they are, break them.

                                      As for the static file, they only wontfix’d it because it’s a feature proposal: https://code.djangoproject.com/ticket/35900

                                      It seems fine to just make it into a feature proposal. It’s not a vuln, I think it’s reasonable for them to ask you to go through that process if you want to see that change.

                                      1. 2

                                        I use this pattern in a bunch of my projects:

                                        DEBUG = os.environ.get("DJANGO_DEBUG")
                                        

                                        Then I run my development server like this:

                                        DJANGO_DEBUG=1 ./manage.py runserver
                                        

                                        Enforcing that DEBUG can only be a boolean would cause an error in these existing projects.

                                        Not a partly serious error - I could fix it by switching to:

                                        DEBUG = bool(os.environ.get("DJANGO_DEBUG"))
                                        

                                        Just pointing out that even something as small as this still counts as a breaking change.

                                        1. 4

                                          They can just put it behind a major version. But just to be clear, I would be fine with them also accepting 0 or 1 and do not buy the argument of “if we have to do it for this we have to do it for everything”.

                                          1. 3
                                            $ DEBUG=0 python -c 'import os; print(bool(os.environ.get("DEBUG")))'
                                            True
                                            

                                            It seems like a footgun, using 1 to mean enabled, when the only disabled value is the empty string or an unset variable.

                                            1. 2

                                              DEBUG = bool(int(os.environ.get("DJANGO_DEBUG")) works, but then it blows up if you leave DJANGO_DEBUG empty. I think if you want it to really be safe, there either has to be a clearly breaking change, or someone has to do some non-trivial parsing and error handling on the DEBUG value or its source, and I know which one is going to be easier to debug.

                                              1. 1

                                                os.environ.get("DJANGO_DEBUG") == "1" would do the trick, better safe than sorry (but slightly more parsing would still be better so you can warn on unknown values).

                                        2. 2

                                          I’m surprised by the “bonus”: a view returning 500 Internal server error when the user posts junk is not very elegant, sure, but it’s not something one can seriously exploit either. All points raised can be fixed on the application side. As discussed in linked tickets, fixing those in the framework can hurt too, especially existing installations. Django security seems to make reasonable compromises.

                                          1. 4

                                            a view returning 500 Internal server error when the user posts junk is not very elegant, sure, but it’s not something one can seriously exploit either.

                                            I think the “combined problem” makes this bad - both crashing and showing debug information. This allows attackers to glean something from what the code is doing. Otherwise, an attacker is stuck blindly fumbling their way to an exploit. By having debug mode enabled they get a spotlight-guided tour of your code which… makes things a lot easier.

                                          2. 1

                                            Why not use an out-of-tree tool to audit security of your Django app rather than relying on the framework to include security-by-default features?