Could we change Django’s createsuperuser and changepassword management commands so they show feedback when users type in their password? At least show asterisks, or otherwise the user’s input.
Current status
Currently don’t show any indication of user input when typing. This is by design, from the Python getpass function. To the extent I’m aware it’s only on UNIX systems (and in particular the command line) that password prompts don’t show any feedback. From my personal experience, this behavior is very surprising to beginners, and is a regular source of friction when they’re learning how to use Django (and software development).
For example, the Django Girls tutorial explicitly has to mention this gotcha:
When prompted, type your username (lowercase, no spaces), email address, and password. Don’t worry that you can’t see the password you’re typing in – that’s how it’s supposed to be. Type it in and press enter to continue.
– Django Girls tutorial – Django Admin
Possible improvements
That’s how it’s supposed to be currently, but definitely not how it has to be forever. The trade-offs between UX and security are well known to people in this space. For example, Django definitely has a “Bypass password validation and create user anyway?” feature within those commands. In any case – in addition to being friction for newcomers, it’s not too hard to imagine this indirectly encouraging people to go for simpler passwords than they might otherwise.
My personal preference would be for option #3, as in recent years I think the “Show password” buttons that have become more widespread have proved the benefits of this approach.
I am strongly against option #3. There is imo a massive difference between a “Show password” button and simply showing the password in clear text.
Regarding option #2 I am somewhat torn, I would want to see the amount of code that is needed to support this nicely and safely on linux/mac/windows first – the gain as I see it is minimal (this is probably were we tend to disagree) and not worth adding technical debt.
I would be okay with #1 even though I would prefer it to stay as is on systems where there is an expectation of the current behavior (mainly linux I guess).
What about adding option #4: Show a “help text” before prompting for the password explaining the behavior?
thanks for the feedback! Option #4 “help text” sounds great as an incremental improvement. There are two other related issues this could help with:
It’s not cool to enforce password validation rules without them being communicated to the user (though in the CLI there is a way to bypass them)
It’s not clear the email field is optional
yes, I suggested showing user input because It’s not clear to me that it’d be possible to implement an effective “show password” control on the command line? Aside from respecting some OS-level environment variables perhaps.
Yes, my expectation would also be to try and match expectations. Specifically the login behavior for the operating system?
I don’t think I’ve ever seen this behavior on Windows but I’ve not used it in ages.
On macOS the only thing I know shows no feedback is sudo / su. The main login screen shows feedback, and password creation definitely does.
On Linux – is there no feedback for all password prompts or only specific ones? Is it any different between creating a password, and entering it to log in?
Here’s a direct link to the CPython getpass implementation. The Windows implementation is 20 lines, UNIX one is 65, and then there’s 14 lines to have getpass alias to one or the other. And tests I assume.
If those figures don’t seem right for Django, I’d hope we could at least encourage one of our contributors to consider making the change in CPython? It is a big accessibility issue for us so certainly worth trying to improve somewhere.
Like @apollo13, I have a preference for option 1 here. I see you’re pushing on that, so would like to see how that goes.
At a higher level, it’s not so much the number of lines here but rather whether this kind of thing is something that Django should be getting involved in. We make a web framework. OS/terminal level input masking is a different activity, and not one that we’re particularly versed in. “Oh, it’s simple” said absolutely everyone who home-rolled their own security sensitive code.
Even if we get it right first time, there’s a persistent risk of introducing an issue at every alteration. (of our own code, and admittedly rarely, on supported platforms.) So, the maintenance burden is lines of code times a multiplier for review, outside of core competency, that we don’t really want to take on.
Not easily, I mean you can always write a curses interface (ie via textual) but that is completely out of scope here
I would say on the Linux shell there is (was?) the assumption that the password is not shown. But Linux being Linux it is not 100% consistent (which is why I would be okay with asterisks, although I think it is not the majority behavior). This is what systemd does for instance:
The “(no echo)” actually goes away when you start typing.
Yes, so this is probably the lower limit of code we have to add. Looking at the alternative implementation linked in the CPython issue (maskpass) we already see ~320 lines (granted with comments but without tests if my quick glance is right) and that is without taking dependencies into account that apparently require a C-compiler given the comment in the maskpass README about install python-devel. So yeah, I am very much against adding a terminal emulator to Django, let’s not work around bugs in the low-level tooling that we use by introducing our own subpar implementation of it.
Ok, just my 2¢ here: On linux I was never surprised, that there is no output at all while entering a password with the management command. Most system command line tools I know don’t produce any output while entering a password. Not login, not passwd, not su and I’m sure many more. Maybe except systemd tools, but systemd does many things differently and I wouldn’t say it represents a “standard” behavior.
So from my view it would be sufficient to leave password entry as it is now, but add some help text, that explains that there is no output of any kind to be expected.
@shangxiao could you elaborate? Is your rationale that the possible improvements aren’t worthwhile for the people who do find the current behavior problematic, or that there isn’t a problem to start with?
We need to look beyond our contributors’ personal experiences here because we skew heavily towards command line proficiency. I’d suspect people here probably have a sense they shouldn’t even be using passwords to start with, except for the convenience in local development, where it doesn’t really matter what disposable password you’re entering anyway. So we need to think of whether there are worthwhile changes for people who are new to Django, possibly new to the CLI world.
I think you’re conflating two things here. On Mac and Linux, it’s standard to not show the password in the CLI, but if you use a curses interface or GUI, it’s expected to see masked input by default.
Since we’re dealing with the CLI here, I’d expect UNIXlike systems to not show input.
The question then raises in my mind if most Mac users use the terminal enough to understand this, and it’s maybe worth thinking about, but I personally still err towards not showing anything here.
@thibaudcolas hmm… so… I don’t think this is worth changing for something that folks are going to be surprised as a 1 off thing I also don’t like to mess with security related practices to make things easier for folks
I’ve never had anyone complain about setting passwords or the Django CLI in general but there are a lot of other things that people criticise Django for like the documentation for eg. I don’t want to get off topic here but in short I just think this is something that would be waaay down the bottom of the list
I hope this response doesn’t put a dent in your enthusiasm I appreciate your efforts with other stuff even if I don’t say so (been idle for a few months too).
Why? NIST Password Guidelines 2024 | AuditBoard argues pretty strongly that you should show the password (but again, as I said above: we should probably erase it on enter so it’s not in the scrollback buffer).
All small details add up. The difference between a great system and a horrible system is almost always a thousand small details that make one feel like petting a cat, or like dragging your face across sandpaper. Every small detail is irrelevant, but together they are everything.
This is what sp800-63b section 5.1.1.2 actually says (emphasis not mine, this is the standard SHOULD/etc formatting and not yelling) :
In order to assist the claimant in successfully entering a memorized secret, the verifier SHOULD offer an option to display the secret — rather than a series of dots or asterisks — until it is entered. This allows the claimant to verify their entry if they are in a location where their screen is unlikely to be observed. The verifier MAY also permit the user’s device to display individual entered characters for a short time after each character is typed to verify correct entry. This is particularly applicable on mobile devices.
The way I read this is that we should provide an option to toggle the visibility of the password input (though I guess this might simply be not worth it given the amount of code we have to add) but I do not see them arguing strongly for it. They most certainly do not recommend to show it fully while typing by default (unless I miss a section which I don’t want to rule out – if that is the case please link me to the section).
It’s an interesting topic, for sure, involving security and usability.
I would prefer to give up as little as possible on the security front, and showing the asterisks might be the best compromise.
But I would definitely not want to implement this directly in Django, rather I would try to contribute to adding this functionality directly in Python, even if this means waiting a bit longer (after all, the feature has been like this for almost twenty years).
It would also be interesting to know how other projects, Python-based or otherwise, handle this aspect.