* Replace bcrypt challenge auth with direct password comparison
Closes#2428
Highlights:
* Replaced the bcrypt challenge authentication flow with direct password comparison against the bcrypt hash stored in the user configuration.
* Removed the `bcrypt.js` dependency, so authentication no longer depends on JavaScript.
* Removed the nonce and challenge mechanism and the `nonce` endpoint from the `javascript` controller.
* Removed the JavaScript and HTML code used for the previous authentication flow.
* Removed the `<noscript>` blocks that were only needed for the previous authentication flow.
* Updated `FreshRSS_FormAuth::checkCredentials()` to accept the username, stored bcrypt hash, and plain-text password directly.
* The stored password hash must still use the expected bcrypt format.
* Empty or whitespace-only passwords are rejected even if the hash would otherwise match.
* The bcrypt 72-byte limit is enforced during normal authentication.
* Existing bcrypt passwords are handled correctly when the 72-byte limit cuts through a UTF-8 character.
* Password input is no longer trimmed before authentication or password changes. Leading and trailing whitespace is therefore kept as part of the password.
* Added `FreshRSS_FormAuth::passwordRequirementsMet()` to replace `FreshRSS_password_Util::check()`.
* New passwords must be between 7 and 72 bytes by default.
* The minimum length check can be disabled where needed.
* Password requirements are now checked server-side for all password creation and update paths.
* Added client-side byte-length validation for password fields using `TextEncoder` and `data-max-bytes`.
* This gives better feedback for UTF-8 passwords.
* Server-side validation remains authoritative.
* Updated password handling in authentication, re-authentication, self-deletion, user creation, and user update paths so passwords are not trimmed automatically.
* Added `FormAuthTest` to cover:
* password length limits in bytes
* UTF-8 passwords around the 72-byte limit
* bcrypt truncation behavior during authentication
* malformed and non-bcrypt hashes
* empty passwords
* authentication failures and log messages
* Removed `bcrypt.js` from the documented dependencies and updated the authentication documentation.
* Updated the installation and authentication views and JavaScript to match the new password handling.
This simplifies the authentication flow, removes the client-side bcrypt challenge, makes password validation consistent between the client and server, and adds more test coverage while keeping compatibility with existing bcrypt password hashes.
Because the password is now sent directly to the server instead of being processed by `bcrypt.js`, deployments should use HTTPS. Documentation for HTTPS setup can be handled separately.
* Add test case with password truncated down to 71 characters
* Compare log messages too during form auth tests
* Mark the `getLastLog()` method as impure
* Fix: Check password reqs against new password instead of current
* Fix: Add custom JS validator for UTF-8, handle cut-off UTF-8 during login
* Fix: Enforce password requirements everywhere server-side
* Add TODO for updateUser in CLI
* make readme
* Fix extra.js in install.php
* Don't report validity yet if the password is too short or not filled out
* Simplify checking of whether to report validity
* Fix: Do not trim password from user's input
* Also `trim: false` in some userController paths
* Use the proper argument order for PHPUnit's `assertSame()`
* Remove `maxlength` in favor of `data-max-bytes`
But add `pattern` again for some nojs support
* make readme
* composer run-script translations
* Update i18n string for web form admin setting
* i18n: fr
* Minor whitespace
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* New hook: `Minz_HookType::AutofillField` for auth views
Currently to be used in the Demo extension, because it overrides both the formLogin and reauth views (for autofilling username/password), it can be broken every time there is a slight change in core.
For example, after https://github.com/FreshRSS/FreshRSS/pull/9358.
In the future the hook can be extended to support more fields.
Demo extension PR: https://github.com/FreshRSS/xExtension-Demo/pull/6
* Suggested alternative without returning HTML code
* auth: make the login challenge nonce one-time
The per-login challenge nonce stored in the session was never consumed or
cleared, so a captured challenge stayed replayable and survived logout
(CWE-294). The client (p/scripts/extra.js) already fetches a fresh nonce for
every attempt, so consuming it does not affect legitimate retries.
Consume the nonce (unset it) as soon as it is read for verification in form
login, reauthentication, password change and account self-deletion, and clear
it in FreshRSS_Auth::removeAccess so logout invalidates any outstanding
challenge.
* auth: don't clear the nonce in removeAccess (breaks login)
removeAccess() runs on every unauthenticated request via FreshRSS_Auth::init()
-- including the login POST itself, before formLoginAction reads the nonce -- so
clearing it there rejected every login with 'Invalid session'. Thanks
@jamalkamaladdin for the measured catch. The one-time guarantee is preserved by
consuming the nonce when it is read for verification (login/reauth/password
change/self-deletion); logout no longer needs a separate clear.
This is done by getting rid of the CSRF check allowlist, and instead of refreshing the CSRF token on every unauthenticated page load, only refreshing the token when needed (on login, logout, account delete, HTTP auth user change)
In addition, the actualize actions are now correctly protected as well.
The most notable part is that the user create action could potentially be exploited by another website for XSS on a given instance, by submitting the register form with known credentials, and then by the attacker logging into the same account forcibly registered by a malicious website, and setting custom User JS code.
Login action was likely not exploitable in any meaningful way, because of the JS nonce.
It's worth noting one risk of merging this PR, some vulnerabilities discovered in the past had reduced impact due to CSRF token refreshing on every page load: https://github.com/FreshRSS/FreshRSS/security/advisories/GHSA-jf4v-f8p2-8xvq#:~:text=It%27s%20important,FreshRSS%5FAuth%3A%3AremoveAccess%28%29%2E
* Housekeeping lib_rss.php
`lib_rss.php` had become much too large, especially after https://github.com/FreshRSS/FreshRSS/pull/7924
Moved most functions to other places.
Mostly no change of code otherwise (see comments).
* Extension: composer run-script phpstan-third-party
Follow-up to #7762
* Regenerate session ID on login
* Send only one cookie
* Improvements
* Delete old session file
* Simplify
* Make function consistent with others
* Implement sudo mode / reauthentication
* i18n: fr
* generate flags
* Improvements
* Remove HMAC check
* Don't require reauth to access logs when signed in as admin
* Notify user of bad login via notification instead
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Minor update whitespace PHPCS rules
To simplify our configuration, apply more rules, and be clearer about what is added or removed compared with PSR12.
Does not change our current conventions, but just a bit more consistent.
* Forgotten *.phtml
* Sort exclusion patterns + add a few for Extensions repo
* Relaxed some rules
The notification about wrong login was not working. Noticed while working on https://github.com/FreshRSS/FreshRSS/pull/5955
This was due to timing of when the notification is retrieved.
Simplified code to make the logic easier and more robust.
* Pass PHPStan level 8
And prepare for PHPStan level 9 https://phpstan.org/user-guide/rule-levels
* Revert wrong replace in comment
* Fix PHPStan level 8
* Update PHPStan and other dev dependencies
* Remove obsolete comment
* noVariableVariables and towards bleedingEdge
https://github.com/phpstan/phpstan-strict-ruleshttps://phpstan.org/blog/what-is-bleeding-edge
* More bleedingEdge
* A bit more PHPStan level 9
* More PHPStan level 9
* Prepare for booleansInConditions
Ignore int and null
* Revert wrong line
* More fixes
* Fix keep_max_n_unread
* Stricter attribute functions
* Stricter callHooks and more PHPStan level 9
* More typing
* A tiny more
* Little's optimisations and booleans in conditions
* Apply strict type
* Apply strict type
* Apply strict type
* Fix multiple bugs with PHP 8.2 and 8.3
* Many declares missing, more errors fixed
* Apply strict type
* Another approach
* Stronger typing for Minz_Session
* Fix case of SQLite
---------
Co-authored-by: Luc <sanchezluc+freshrss@gmail.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* processing of depreciations and updating of code to php7.2 minimum
* Autoformat many strange array indenting
And revert a few unwanted changes
---------
Co-authored-by: Luc <sanchezluc+freshrss@gmail.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Modernize Constants and use new constant 'currentUser'
* Add FreshRSS_Context::currentUser() function and use
* Add FreshRSS_Context::currentUser() function and use
* Add FreshRSS_Context::currentUser() function and use
* Add FreshRSS_Context::currentUser() function and use
* Add FreshRSS_Context::currentUser() function and use
* Update app/Controllers/userController.php
* Update app/Controllers/userController.php
* Update app/Controllers/userController.php
* Update app/Models/Auth.php
* Update p/api/greader.php
* Update p/api/greader.php
* Update p/api/greader.php
* Update app/Models/Context.php
* Update app/Models/LogDAO.php
* Update lib/Minz/Log.php
* Update p/api/greader.php
* Update app/layout/header.phtml
* Update app/views/helpers/export/articles.phtml
* Update cli/do-install.php
* Remarque's from Alkarex
* Remarque's from Alkarex
* Refactor using new Minz_User class
* Consistent naming of public constants
---------
Co-authored-by: Luc <sanchezluc+freshrss@gmail.com>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Typehint to Controllers
* Remarque's from Alkarex
* Remarque's from Alkarex
* Remarque's from Alkarex
* Remarque's from Alkarex
* Remarque's from Alkarex
* Remarque's from Alkarex
---------
Co-authored-by: Luc <sanchezluc+freshrss@gmail.com>
* Use constants for path to TOS
* improve comments
* TOS title moved to template
* TOS available via config menu
* CSS: improve handling of content of TOS/about
* give info about set/unset TOS in system config
* fix target
* i18n FR
* i18n DE
Before, if you've tried to reach a page without being logged, you'll be
automatically redirected to the index page after login.
Now, the original page is used after login.
Fix#3663
* Use typographic quotes
* A few fixes
* Fix
* Fix not saved
* Implement feedback
* Detail
* Revert spoken English fixes
Left for a future dedicated discussion
* More reverts
* Final reverts
* Final minor