Repository: pallets/werkzeug (python)

Issue:
Increase default work factor for PBKDF2 to 600,000 iterations
https://github.com/pallets/werkzeug/blob/bba2109e276ab876b8d64e2b967412cb6da1d865/src/werkzeug/security.py#L12

The value has not been updated for a few years. I propose increasing it to the same number as the next release of Django will use.

See https://github.com/django/django/pull/16521 and https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2.

Pull request description:
Increase default work factor for PBKDF2 to 600,000 iterations
Increase default work factor for PBKDF2 from 260,000 to 600,000 iterations to match [an OWASP recommendation](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2).

- fixes #2611

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [ ] Add or update relevant docs, in the docs folder and in code.
- [x] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [ ] Add `.. versionchanged::` entries in any relevant code docs.
- [x] Run `pre-commit` hooks and fix any issues.
- [x] Run `pytest` and `tox`, no tests failed.


Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 58eb407f..328fa6f4 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -31,6 +31,7 @@ Unreleased
     Watchdog to 2.3.0. :issue:`2603`
 -   When using a Unix socket for the development server, the path can start with a dot.
     :issue:`2595`
+-   Increase default work factor for PBKDF2 to 600,000 iterations. :issue:`2611`
 
 
 Version 2.2.3
diff --git a/src/werkzeug/security.py b/src/werkzeug/security.py
index 4599fb3e..0ae4a36e 100644
--- a/src/werkzeug/security.py
+++ b/src/werkzeug/security.py
@@ -9,7 +9,7 @@ if t.TYPE_CHECKING:
     pass
 
 SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-DEFAULT_PBKDF2_ITERATIONS = 260000
+DEFAULT_PBKDF2_ITERATIONS = 600000
 
 _os_alt_seps: t.List[str] = list(
     sep for sep in [os.sep, os.path.altsep] if sep is not None and sep != "/"


Test patch:
diff --git a/tests/test_security.py b/tests/test_security.py
index 3e797fcc..609170cd 100644
--- a/tests/test_security.py
+++ b/tests/test_security.py
@@ -11,7 +11,7 @@ from werkzeug.security import safe_join
 def test_password_hashing():
     hash0 = generate_password_hash("default")
     assert check_password_hash(hash0, "default")
-    assert hash0.startswith("pbkdf2:sha256:260000$")
+    assert hash0.startswith("pbkdf2:sha256:600000$")
 
     hash1 = generate_password_hash("default", "sha1")
     hash2 = generate_password_hash("default", method="sha1")