Client-accessible headers are used to send authentication information to other middlewares
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
OpenStack Object Storage (swift) |
Fix Released
|
Undecided
|
Unassigned | ||
OpenStack Security Advisory |
Won't Fix
|
Undecided
|
Unassigned | ||
Swift Authentication |
Fix Released
|
Undecided
|
Unassigned | ||
Swift3 |
Fix Released
|
Undecided
|
Unassigned | ||
keystonemiddleware |
Won't Fix
|
Undecided
|
Unassigned |
Bug Description
Given knowledge of the HTTP method, path, and headers of a past
request, an attacker can completely impersonate the user from that
request for any method against any path.
For example, suppose a proxy has `access_log_headers = True` enabled in its
proxy-logging filter config. This will produce log lines[1] like
> Mar 21 16:15:16 vagrant-
... which includes the method ("GET"), path ("/"), and headers:
Authorization: AWS test:tester:
User-Agent: Boto/2.38.0 Python/2.7.10 Darwin/15.3.0
Date: Mon, 21 Mar 2016 16:15:16 GMT
Host: saio:8080
Accept-Encoding: identity
Content-Length: 0
Content-Type: None
Using the method ("GET"), path ("/"), and the Date header, an attacker
can construct the AWS-standard "canonical request" and base64 it:
GET
Mon, 21 Mar 2016 16:15:16 GMT
/
Base64 encoded:
R0VUCgoKTW9uL
Using this base64-encoded value and the Authorization header from the
original intercepted request, an attacker can create a new request to
a different endpoint. This new request will be successful.
$ curl -sv http://
-H 'X-Auth-Token: R0VUCgoKTW9uLCA
-H 'Authorization: foo test:tester:
* Trying 192.168.8.80...
* Connected to saio (192.168.8.80) port 8080 (#0)
> GET /v1/AUTH_
> Host: saio:8080
> User-Agent: curl/7.43.0
> Accept: */*
> X-Auth-Token: R0VUCgoKTW9uLCA
> Authorization: foo test:tester:
>
< HTTP/1.1 204 No Content
< Content-Length: 0
< X-Container-
< Accept-Ranges: bytes
< X-Storage-Policy: default
< X-Container-
< X-Timestamp: 1458350360.97314
< Content-Type: text/html; charset=UTF-8
< X-Trans-Id: tx332c5891eff84
< Date: Mon, 21 Mar 2016 16:29:33 GMT
<
The reason this "works" is because of the way the Authorization and
X-Auth-Token headers are parsed by the swift3 middleware and auth
middleware. When Swift3 sees the Authorization header, it checks that
it starts with "AWS". If so, Swift3 assumes it's a request to to be
translated from S3 to Swift and puts the base64-encoded canonical
request into the X-Auth-Token header. The auth system sees the
Authorization header and then goes into S3-validation mode. In this
mode, it decodes the value of the X-Auth-Token header, signs that with
the user's secret key, and compares it to the signature in the
Authorization header. If they match, then the request is authorized.
Importantly, the auth system does not validate that the Authorization
value starts with "AWS". Even if it did, however, a similar exploit
is possible if swift3 is ever removed from the pipeline.
Because of this buggy interaction, the attacker may use this same
Authorization/
user can access, not just the resource from the intercepted request.
Notes:
* "AWS" has been changed to "foo" in the original Authorization header. This
ensures Swift3 will treat the request as a Swift (not S3) request [2].
As a result:
- Swift3's clock-skew check is bypassed, so any captured request (no matter
how old) may lead to an exploit.
- The full "/v1/AUTH_
"/container").
* While Swift3 treats this as a Swift request, all known authentication
middlewares that support swift3 (s3_token, swauth, and tempauth) will treat
this as a S3 request. This is because none of them verify the first piece
of the Authorization header [3].
* While a proxy-server log was used to demonstrate this attack, comparable
information may be obtained from client debug logs or man-in-the-middle
attacks.
Affected Versions:
* s3_token middleware:
- keystonemiddlew
Patches necessary on master, stable/mitaka, stable/liberty, stable/kilo
- python-
Patches necessary on stable/liberty, stable/kilo
- keystone>
No longer supported; no patches necessary
* swauth middleware:
- swauth>=1.0.1
Patch necessary on master only; no stable branches
- swift>=1.3.0,<1.4.1
No longer supported; no patches necessary
* tempauth middleware:
- swift>=1.4.1
Patch necessary on master only; tempauth is not expected to be used in
production.
Proposed Solution:
Swift3 should not use client-accessible headers for cross-middleware
communication. Rather, it should claim its own namespace in the WSGI
environment (say, "swift3.
and normalized request there. Note that this would be a breaking API change.
Swift3, like Swauth, does not use stable branches; however, it claims support
for Swift 2.1.0 (Juno). As a result, kilo and liberty deployments can upgrade
to the latest swift3 middleware when upgrading s3_token.
Patches against master for swift3, s3_token, swauth, and tempauth are attached,
as well as a patch against stable/liberty for python-
master patches have been tested manually; additionally, the combination of the
swift3, s3_token, and tempauth patches allows swift3's functional tests to
pass.
[1] http://
[2] https:/
[3] https:/
https:/
https:/
information type: | Private Security → Public Security |
description: | updated |
Changed in swauth: | |
status: | New → Fix Committed |
status: | Fix Committed → Fix Released |
Because this is an issue in Swift with tempauth, which only exists for testing and is not a production auth system, I do not think this is a security issue in Swift itself.
However, since this is an issue with the interaction of several projects as it relates to S3 access in Swift, and because it's based on the way auth works in Swift, I asked Tim to submit it agains Swift as a coordination point for this bug.