-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implements request body validation inside HmacAuth #2419
Implements request body validation inside HmacAuth #2419
Conversation
@vaibhavatul47 please address the linting error and test failures: https://travis-ci.org/Mashape/kong/builds/223708709 |
68dd044
to
3a1bc87
Compare
@vaibhavatul47 there is still a failure in the test:
Mind taking a look? |
@p0pr0ck5 This is expected behaviour as of now. The test which is failing depends on checking mandatory params for hmac-headers. This is implemented in PR #2418. I had already mentioned in above comments that few test cases will fail until #2418 will be merged. |
@p0pr0ck5 and @shashiranjan84 will review this, as it is in need of a few improvements :) We will also need a documentation PR on getkong.org :) Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small cleanup comments, nothing major.
kong/plugins/hmac-auth/access.lua
Outdated
@@ -82,11 +87,26 @@ local function create_hash(request, hmac_params, headers) | |||
return ngx_sha1(hmac_params.secret, signing_string) | |||
end | |||
|
|||
local function is_signature_equal(signature_1, signature_2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the purpose of this function? constant time comparison? if so, please see 7345134 as to why this approach is incorrect; otherwise, please elaborate :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I mentioned the wrong commit. I should have typed 6ccdf7b :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed this function as no more required.
kong/plugins/hmac-auth/access.lua
Outdated
@@ -152,7 +188,7 @@ local function set_consumer(consumer, credential) | |||
else | |||
ngx_set_header(constants.HEADERS.ANONYMOUS, true) | |||
end | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change seems unwarranted? please remove it.
kong/plugins/hmac-auth/access.lua
Outdated
@@ -173,10 +209,21 @@ local function do_authentication(conf) | |||
if not hmac_params.username then | |||
hmac_params = retrieve_hmac_fields(ngx.req, headers, AUTHORIZATION, conf) | |||
end | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idem
kong/plugins/hmac-auth/access.lua
Outdated
@@ -189,7 +236,7 @@ local function do_authentication(conf) | |||
|
|||
-- Retrieve consumer | |||
local consumer, err = cache.get_or_set(cache.consumer_key(credential.consumer_id), | |||
nil, load_consumer_into_memory, credential.consumer_id) | |||
nil, load_consumer_into_memory, credential.consumer_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this whitespace change is incorrect, please remove it.
kong/plugins/hmac-auth/access.lua
Outdated
function _M.execute(conf) | ||
|
||
if ngx.ctx.authenticated_credential and conf.anonymous ~= "" then | ||
-- we're already authenticated, and we're configured for using anonymous, | ||
-- we're already authenticated, and we're configured for using anonymous, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please avoid whitespace changes like this, as it dirties the commit history and makes future archaeological efforts more challenging.
kong/plugins/hmac-auth/access.lua
Outdated
@@ -213,7 +259,7 @@ function _M.execute(conf) | |||
if conf.anonymous ~= "" and conf.anonymous ~= nil then | |||
-- get anonymous user | |||
local consumer, err = cache.get_or_set(cache.consumer_key(conf.anonymous), | |||
nil, load_consumer_into_memory, conf.anonymous, true) | |||
nil, load_consumer_into_memory, conf.anonymous, true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idem, please remove this unnecessary whitespace change.
@@ -129,6 +149,22 @@ local function validate_clock_skew(headers, date_header_name, allowed_clock_skew | |||
return true | |||
end | |||
|
|||
local function validate_request_body(headers, body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ietf draft indicates that a digest header may look something like:
digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=\n
It doesn't appear that the generate hash will match such a format, with the form of the hash prepended to the base64-encoded hash itself. Do we care about this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote my logic assuming Kong will always check the SHA-256 hash of request body.
As per ieft draft, the user can use any hash algorithm to generate the hash. If we allow this, then for each request, Kong would need to parse Digest
header and then figure out which hashing algorithm to use. Then there could be cases where a user uses an algorithm not supported by Kong libraries.
So for simplicity, I assumed only SHA-256.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do one thing to abide by ieft draft.
At Kong, we can generate hash string prepended by the hash algorithm as recommended by draft, i.e.:
digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=\n
Then we would need to mention it clearly that user needs to send digest header in this format and only sha-256
algorithm is supported by Kong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vaibhavatul47 please also rebase to next
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vaibhavatul47 i think this is a good approach, as it could allow us to support additional algorithms in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've fixed this.
9cdee84
to
941c012
Compare
LGTM, @vaibhavatul47 would you be able to adjust your commit message based on https://github.com/Mashape/kong/blob/master/CONTRIBUTING.md#commit-message-format? @shashiranjan84 any thoughts here? |
local sha_recieved = headers[DIGEST] | ||
|
||
if body == nil then | ||
return true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style, needs a blank line after return. not a blocker, we can adjust this as part of merge
@vaibhavatul47 @p0pr0ck5 overall LGTM, I'll format it to latest code style before merge. |
Currently, Hmac-Auth plugin allows validation of only request headers. There are requirements in real life projects when the validity of requestbody is also to be verified. To solve this problem I have introduced the usage of digest header. This digest header will contain the Base64 encoded Sha256 hash of the request body. If an API has hmac-auth plugin enabled and validate-request-body config is enabled then for every request of this API received at KONG, Hmac-Auth plugin will also validate the integrity of request body, needless to say, this check will be performed only if request contains any body. If this config( validate-request-body) is enabled on an API then every request must contain digest header inside hmac-headers parameter. Changes committed: modified: kong/plugins/hmac-auth/access.lua Added function which will validate request body modified: kong/plugins/hmac-auth/schema.lua added new config parameter: `validate_request_body` modified: spec/03-plugins/20-hmac-auth/03-access_spec.lua added multiple tests for this feature.
941c012
to
704f47d
Compare
@p0pr0ck5 I've updated commit message. |
if body == nil then | ||
return true | ||
elseif sha_recieved == nil then | ||
return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vaibhavatul47 here your logic forcing client to send digest
header. I would prefer logic to be
if validate_request_body and headers[digest] then
validate digest
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ll update the code and tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vaibhavatul47 here is what I am thinking to change it to
-- If request body validation is enabled, request may require `digest` validation
local digest_recieved = headers[DIGEST]
if conf.validate_request_body and digest_recieved then
if not validate_digest(digest_recieved) then
return false, {status = 403, message = SIGNATURE_NOT_VALID }
end
end
-----------------------
local function validate_digest(digest_recieved)
req_read_body()
local body = req_get_body_data()
-- request must have body as client sent
-- a digest header
if not body then
return false
end
local sha256 = resty_sha256:new()
sha256:update(body)
local digest_created = "SHA-256=" .. ngx_encode_base64(sha256:final())
return digest_created == digest_recieved
end
I will also work on adding support for other hashing algorithm, at least SHA1 and SHA-256 for both Digest and HTTP signature validation. May be a new PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shashiranjan84 if validate_request_body is enabled then forcing client to send digest header is important. If this is not mandated then someone who can change request body would also delete digest header and then this corrupted request would be validated by plugin as it didn't contain any digest header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vaibhavatul47 Not really, If signature is created using digest, it would not pass validation as it is tampered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -177,6 +198,16 @@ local function do_authentication(conf) | |||
return false, {status = 403, message = SIGNATURE_NOT_VALID} | |||
end | |||
|
|||
-- If request body validation is enabled, then verify hash of request body. | |||
if conf.validate_request_body then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also we should validate headers first and then body. As if header is tampered there is no point validating body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shashiranjan84 I'll update code according to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't, I already updated the code. Planning to merge it today
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Closing this PR in favor of #2613. |
#2613 was merged, thank you @vaibhavatul47 for your contribution! |
Summary
Adding functionality to validate request body in hmac-auth. This is optional and can be configured when enabling the Hmac-Auth plugin for an API.
Full changelog
Currently, Hmac-Auth plugin allows validation of only request headers. There are requirements in real life projects when the validity of request body is also to be verified. To solve this problem I have introduced the usage of digest header. This digest header will contain the Base64 encoded Sha256 hash of the request body.
If an API has hmac-auth plugin enabled and validate-request-body config is enabled then for every request of this API received at KONG, Hmac-Auth plugin will also validate the integrity of request body, needless to say, this check will be performed only if request contains any body
If this config( validate-request-body) is enabled on an API then every request must contain digest header inside hmac-headers parameter.
Tests added
should not pass with POST when body validation enabled and digest header missing from hmac-headers( This test will be added in Feature/check mandatory headers in hmac param #2418 )