mirror of
https://github.com/motioneye-project/motioneye.git
synced 2026-03-02 22:57:06 -05:00
Admin password in SHA1, normal password in plain text #2656
Labels
No labels
Android app
Arch Linux
CI/CD
CSS
FreeBSD
HTML/HTTP
Home Assistant addon
JavaScript
Python
Raspberry Pi
Stale No Activity 60 Days
bug
code format
dependencies
dev branch
docker
documentation
duplicate
enhancement
feature
help wanted
i18n/l10n
invalid
legacy motionEye
meta
motion
motionEyeOS
notourproblem
python update
question
question
security
troubleshooting
wontfix
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/motioneye#2656
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @SuMaPa on GitHub (Nov 17, 2025).
Hi
Sha1 is a little better than plaintext.
So I changed the normal password to SHA1 in the config.py file. Works perfectly.
I haven't been able to switch to >SHA1 yet. Password generation works, but the login doesn't.
I was able to gather some insights. However, a bypass solution will then be needed.
@MichaIng commented on GitHub (Nov 17, 2025):
When touching this, we'd need to keep supporting the old hashing algorithm for reading the password, but we may want to force users to set/change it once, to have it stored in new format ASAP. However, does not make much sense to use insecure SHA1. At best we switch to Argon2ID, or minimum bcrypt.
@MichaIng commented on GitHub (Nov 17, 2025):
Btw, regarding normal/surveillance user password, AFAIK the reason to store it in plain text was that it is reused as direct
motioncamera password, also used by motionEye to access those streams. Hence storing it hashed would break access. Not an awesome implementation, but I have no other great idea how to do better: motionEye could use some internal-only random password to accessmotion, that is independent of the surveillance user password used to authenticate at motionEye. But that would break direct access to those streams for users, bypassing motionEye interface. The idea surely was to keep it simple, having one surveillance user password to access motionEye read-only, as well as accessmotioncamera streams directly. And AFAIK there is no way to have two passwords for amotioncam, to allow access via surveillance user password, while motionEye uses an own internal one that is not exposed in any UI.@zagrim commented on GitHub (Nov 17, 2025):
Different hash algorithms produce hashes of different lengths (and have even distinctly recognisable formats, see examples in Hashcat docs), so this shouldn't be too difficult 🤔
Yeah, not to mention that the password for accessing Motion (be it only used internally by ME or not) needs to be stored in plaintext anyway, so having a more secure read-only access to ME UI might not make much sense 🤔 I mean, if someone could read the surveillance user password from ME config, that same attacker could just as fine read the password from Motion config and anyway access Motion directly. The original design of Motion wasn't done with much regard for security, and that was pretty normal back then I guess so I'm not blaming anyone here. I guess it just is one of those things that needs to be guarded from outside access by all means and on all levels if security is a requirement.
@SuMaPa commented on GitHub (Nov 17, 2025):
I'm not sure if I understand you correctly.
In the config.py file, I changed the user to sha1. The SHA1 password was created in the motion.conf file.
All other passwords continue to be stored in plain text. I can't find any restrictions.
Unfortunately, I haven't made any further progress. The SHA256 string is being saved correctly, but it's not being recognized upon login. There might be a hidden character limit somewhere that I haven't found yet.
:( ...postponed until next week
@SuMaPa commented on GitHub (Nov 19, 2025):
user (anyway) and admin name can be changed, possibly a little more security??
@SuMaPa commented on GitHub (Nov 27, 2025):
I'm too stupid for that.
@MichaIng commented on GitHub (Nov 27, 2025):
Sorry for the late reply. So you applied hashing in
config.pyhere, but you could not login afterwards? Did you also implement support for the hash at the authentication part? Here I mean: https://github.com/motioneye-project/motioneye/blob/main/motioneye/handlers/base.py#L115-L135Although, it seems to allow both already:
normal_passwordis a hashnormal_password in (up['password'], hashlib.sha1(up['password'].encode('utf-8')).hexdigest())is true as it matches the 2nd entry: the hashed password header.If this does not work, and authentication fails there, it would need some debug code to find out why.
And yes, the usernames are variables internally already, but in many places of the code they are still hardcoded. Should not be too hard to find and adjust those places, and turn the currently read-only fields in the settings into read-write fields, to change those usernames.
I found the reason why this password is not hashed right now:
motionalso has a webcontrol authentication option, but that is not currently used by motionEye:@SuMaPa commented on GitHub (Nov 27, 2025):
Please do not test on your live system.
It's easy to make the adminusername/ "admin" changeable.
templates/main.html
It is also easy to encrypt the user password using SHA1.
config.py
I tested this on several test installations, and it works very well under Debian (12&13).
Please do not test on your live system.
Anything higher than SHA1 doesn't work.
Passwords are generated correctly (config.py).
Queries are apparently made via utils/init.py (on restart) and handlers/base.py.
Right now I'm just annoyed. Once I've calmed down, I'll add debug code. Maybe.
@MichaIng Everything's fine, we all have work to do.
@MichaIng commented on GitHub (Nov 27, 2025):
That makes sense unless you replace the algorithm everywhere it is used, i.e. in the
base.pyhandler I linked above.See here about updating the algorithm: #2467
@SuMaPa commented on GitHub (Nov 28, 2025):
SHA1 user password works with video streaming.
Video streaming works even when it's switched off. :(
@MichaIng commented on GitHub (Nov 29, 2025):
Oh, that is odd. And indeed the code looks like it would just allow everything, hash, plain, or no authentication for normal/surveillance user. But that the direct stream cannot even be disabled raises the severance of that issue.
The [stream_auth_method[https://motion-project.github.io/motion_config.html#stream_auth_method] allows at least MD5 digest authentication, which hence would allow the normal user password to be stored this way, without breaking double-use of it. Not awesome, but better than plain text. However, inside the
motionconfig, it seems to be still needed in plain text, needs testing.Let me re-open this issue. This whole normal user and direct stream authentication needs some require at least.
@MichaIng commented on GitHub (Feb 14, 2026):
#3268 added dedicated credentials for streaming, so the surveillance/normal user password does not need to be in plain text anymore.
So we can not hash it, and in turn we should apply a stronger algorithm: Argon2ID, yescrypt, bcrypt minimum, I'd say, depending on what is available in standard Python 3 libraries.
For backwards-compatibility/migration we could either check the hash for a SHA1 marker, or simply compare SHA1 as a fallback, if the stronger algorithm did not match, similar to how we compare the unhashed input as fallback as well. And optionally we could print a warning if SHA1 worked, suggestion to update the password (re-enter + save), to migrate to the stronger algorithm.
When changing/saving a password, the strong algorithm should be always used, of course.
@SuMaPa commented on GitHub (Feb 15, 2026):
Hi
I haven't been able to get sha512 working - bcrypt won't make it any better. :)
@MichaIng commented on GitHub (Feb 15, 2026):
Of course bcrypt would make it some magnitudes of order better. This calculator suggests it takes about a million times longer to calculate/brute-force bcrypt vs SHA1: https://kutatua.com/password/time-to-crack-calculator
Of course things depend, but you get the idea. Point is that bcrypt is made for password explicitly hashing, SHA1 isn't.
But true is that bcrypt aged as well, and it doesn't require much RAM to calculate, so cheap parallelism is possible, which yescrypt and especially Argon2 address.
Seems this is a good one to use Argon2: https://pypi.org/project/argon2-cffi/
It will require the C libffi library and the Python cffi module as additional dependencies.
PyNaCl also has a password hashing module, but it seems overkill.
The best standard library alternative would be PBKDF2-HMAC-SHA256: https://docs.python.org/3/library/hashlib.html#hashlib.pbkdf2_hmac
But recently this depends on OpenSSL. Might be rare, but theoretically possible that it is not available in some edge cases 🤔.
@SuMaPa commented on GitHub (Feb 16, 2026):
hi
I see it the same way; it should be encrypted with bcrypt.
I just wanted to express my incompetence.
I wasn't able to upgrade to SHA512. Therefore, I don't need to worry about bcrypt.
Sorry
@MichaIng commented on GitHub (Feb 16, 2026):
Ah right, I remember 😄. I am currently updating the frontend, getting rid of some obsolete cruft and 3rd party scripts. I should find some time after this is done.
In any case, bcrypt, yescript, Argon2 all would require some more work, since this would need to be done with external modules. Only PBKDF2-HMAC-SHA256 is part of hashlib, hence could be applied the very same way as SHA1 is done, for hashing on value change and on input, the latter keeping SHA1 as fallback to not lock out users on upgrade.
But again, PBKDF2-HMAC-SHA256 is not assured to be available, since it requires Python to be build with OpenSSL. So I guess this would be problematic to use. The Argon2 module at least looks simple. Maybe worth to byte the apple and pull this in as additional dependency for the security benefit.