Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b5f77f8c3 |
No files matched your search
@@ -874,9 +874,10 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
- `password` in the JSON body of `/api/v1/admin/users` and each user
|
||||
under it.
|
||||
|
||||
None applies when the query has a parameter of the same name.
|
||||
`' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd` and
|
||||
`<img src=x onerror=x()>` sent as the password reach gitea;
|
||||
Each field listed skips these rules on every path listed, not only on
|
||||
the paths given for it. None applies when the query has a parameter of
|
||||
the same name. `' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd`
|
||||
and `<img src=x onerror=x()>` sent as the password reach gitea;
|
||||
`<script>alert(1)</script>` and `javascript:alert(1)` are still refused.
|
||||
|
||||
Elsewhere these fields keep every rule. The paths are those of gitea at the
|
||||
@@ -955,9 +956,16 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
|
||||
- `pass1`, `pass2` and `post_password` on `/wp-login.php`, which reset a
|
||||
password and sign in to a protected post, for the same rules.
|
||||
- `pass1` and `pass2` on `/wp-admin/profile.php`,
|
||||
`/wp-admin/user-edit.php` and `/wp-admin/user-new.php`, for the same
|
||||
rules.
|
||||
- `pass1` and `pass2` on these pages, for the same rules:
|
||||
- `/wp-admin/profile.php`;
|
||||
- `/wp-admin/user-edit.php`;
|
||||
- `/wp-admin/user-new.php`;
|
||||
- `/wp-admin/network/user-edit.php` and
|
||||
`/wp-admin/user/profile.php`, on a multisite install.
|
||||
|
||||
Each of `pass1`, `pass2` and `post_password` skips these rules on
|
||||
all of these pages and on `/wp-login.php`.
|
||||
|
||||
- `password` in form data or JSON on the REST API's `/wp/v2/users` and
|
||||
the user under it, for the same rules.
|
||||
- `title`, `excerpt` and `name` in a JSON body sent to any REST API
|
||||
@@ -1046,6 +1054,10 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
`/user/register` and `/user/<id>`;
|
||||
- `data.attributes.pass.value` and `data.attributes.pass.existing` in
|
||||
the JSON:API body of `/jsonapi/user/user` and each user under it.
|
||||
|
||||
Each field listed skips these rules on every path listed, not only on
|
||||
the paths given for it.
|
||||
|
||||
- `name` when resetting a password through Drupal's JSON format on
|
||||
`/user/password`, for the same four rules.
|
||||
- `mail` in that same reset, for 932120 and 932260 only.
|
||||
@@ -1293,6 +1305,9 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
933100, 933135, 933180, 933210, 941100, 941120, 941160, 941180, 942100,
|
||||
942151, 942190, 942230, 942290, 942320, 942540, 942550, 944150.
|
||||
|
||||
Each field in the first two items skips these rules on every path in those
|
||||
items.
|
||||
|
||||
`' OR '1'='1`, `../../etc/passwd`, `; cat /etc/passwd` and
|
||||
`<img src=x onerror=x()>` sent as a password reach Mastodon;
|
||||
`<script>alert(1)</script>` and `javascript:alert(1)` are still refused.
|
||||
@@ -1476,6 +1491,9 @@ The changes hold in front of every app, and no setting undoes them:
|
||||
`password`. A body with more than one `key`, or a `key` or `value` in the
|
||||
query, gets none of this.
|
||||
|
||||
Each field listed but `value` skips these rules on every path listed, not
|
||||
only on the paths given for it.
|
||||
|
||||
`password` on `/login/flow/apptoken` and `/login/v2/apptoken` holds a
|
||||
generated app token, so it needs no exclusion.
|
||||
|
||||
|
||||
@@ -979,6 +979,35 @@ func TestPasswordFieldsStayCheckedInTheQuery(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The password exclusions apply in front of every app. So each field keeps
|
||||
// every rule on a nearby path that its exclusion does not name.
|
||||
func TestPasswordExclusionsAreNarrow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
|
||||
|
||||
crs := readingBodies(t)
|
||||
|
||||
for _, sent := range []struct{ target, contentType, name string }{
|
||||
{"/user/settings/profile", formData, passwordKey},
|
||||
{"/api/v1/user/repos", jsonBody, passwordKey},
|
||||
{"/admin/users/overview", formData, "token"},
|
||||
{"/wp-admin/options.php", formData, "pass1"},
|
||||
{"/wp-admin/post.php", formData, "post_password"},
|
||||
{"/user/password", formData, "pass[pass1]"},
|
||||
{"/settings/apps", formData, passwordKey},
|
||||
{"/ocs/v2.php/apps/spreed/api/v4/room", jsonBody, passwordKey},
|
||||
{"/settings/profile", formData, "form_challenge[current_password]"},
|
||||
} {
|
||||
r := request{http.MethodPost, sent.target, []string{sent.contentType}}
|
||||
|
||||
body := passwordBody(t, r, []string{sent.name}, "' OR '1'='1")
|
||||
if got, _ := inspectBody(t, crs, r, body); got.Score < threshold {
|
||||
t.Errorf("POST %s %s let through: %+v", sent.target, sent.name, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGiteaAttacksAreRefused(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1616,6 +1645,8 @@ func TestWordPressPasswordFieldsPass(t *testing.T) {
|
||||
{"/wp-admin/profile.php", formData, pass},
|
||||
{"/wp-admin/user-edit.php?user_id=2", formData, pass},
|
||||
{"/wp-admin/user-new.php", formData, pass},
|
||||
{"/wp-admin/network/user-edit.php?user_id=2", formData, pass},
|
||||
{"/wp-admin/user/profile.php", formData, pass},
|
||||
{"/wp-json/wp/v2/users", jsonBody, []string{passwordKey}},
|
||||
{"/wp-json/wp/v2/users/me", formData, []string{passwordKey}},
|
||||
{"/index.php?rest_route=/wp/v2/users/2", jsonBody, []string{passwordKey}},
|
||||
|
||||
@@ -138,9 +138,11 @@ SecRule REQUEST_FILENAME "@streq /wp-login.php" \
|
||||
|
||||
# The other passwords, which skip the same rules:
|
||||
# pass1, pass2: resetting the password at /wp-login.php, changing it on the
|
||||
# profile page and the page that edits a user, and adding a user
|
||||
# profile page and the page that edits a user, and adding a user; a
|
||||
# multisite install also changes it under /wp-admin/network/ and
|
||||
# /wp-admin/user/
|
||||
# post_password: the password of a protected post, sent to /wp-login.php
|
||||
SecRule REQUEST_FILENAME "@rx ^/(?:wp-login\.php|wp-admin/(?:profile|user-edit|user-new)\.php)$" \
|
||||
SecRule REQUEST_FILENAME "@rx ^/(?:wp-login\.php|wp-admin/(?:profile|user-edit|user-new|network/user-edit|user/profile)\.php)$" \
|
||||
"id:900715,phase:1,pass,nolog,chain"
|
||||
SecRule &ARGS_GET:/^(?:pass[12]|post_password)$/ "@eq 0" \
|
||||
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:pass[12]|post_password)$/,\
|
||||
|
||||
Reference in new issue
Block a user