-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
ValidatePayload should not accept nil or empty secretToken slice #2731
Comments
So you disagree with the consensus reached on #1126 and wish to revert its changes, or just want to return a custom error value when nil is used? |
I defer to others on whether you revert or otherwise. I am just trying to describe what I think is a safe default: |
OK, I think I'll defer to @willnorris on this one. 😁 |
In hindsight, we shouldn't have implemented it this way. It's still fine to have a webhook without a secret (and therefore without a signature) if that's what you really want, but to @myitcv's point, you probably shouldn't be able to circumvent signature verification on a webhook which does have a secret configured simply by passing a nil value. What we probably should have done, and what I'm about to send a PR to update, is to check whether a non-empty secret was passed to the Looking back at the original post in #1126, it sounds like the request was to support webhooks which don't have a secret, which will still be supported with my upcoming change. So I think we can safely make this change without changing the original intent of #1126. |
I make the following point humbly acknowledging I am neither a regular contributor nor a security expert!
Not sure that I agree. If I make a call to Imagine if the relevant header is missing for whatever reason (GitHub error): I would also want that to be caught. Similarly with a configuration error resulting in a Anything else just doesn't feel like a safe default to me. |
huh, I really thought this was doing more than JUST signature validation, which was my main argument for accepting this as a valid use case. It's been years since I've worked with this code regularly, so maybe it used to and doesn't any longer? I'll have to dig in more. |
The tests certainly make it look like it used to validate the event type and event ID as well, though those are no longer used apparently. |
okay, I was wrong about that. This was added in #294, and there was a decent amount of discussion there about what this is doing and the design. It looks like ValidatePayload has only ever handle signature checking, and the eventID present in the tests was just accidental and has never actually been used. That said, I still think the change I described above is correct, and actually for the reasons you state:
I would also extend to that to say that if I call ValidatePayload with a nil secretKey, then I'm explicitly stating that I do not expect a signature to be present, and if one IS present then something may be wrong. If we instruct callers to simply not call ValidatePayload at all for webhooks that don't have configured secrets, then they are missing that protection.
Both scenarios would be caught in my proposed change. If you indicate that you are expecting a signature to be present, but it's not, then that's an error. If you pass a nil secret token (either because of a configuration error or intentionally), but a signature is present in the payload, then that's an error also. The only scenario this would not handle is when both of the above are present at the same time... a GitHub error mistakenly omits the Signature header AND a configuration error passes a nil secret token. A call to ValidatePayload() would pass, since both sides match. Though that seems far-fetched enough to not worry about. |
Verify the payload signature if the request has a signature present in HTTP headers, or if a non-empty secretToken is passed to the ValidatePayload method, indicating that a signature is expected. This modifies the behavior added in #1127, but not the spirit of what was requested in #1126, which is to support webhooks that don't have configured secrets. Specifically, this no longer allows signature checking to be skipped entirely, even for webhooks with a configured secret, simply by passing an empty secretToken to ValidatePayload. Fixes #2731
Verify the payload signature if the request has a signature present in HTTP headers, or if a non-empty secretToken is passed to the ValidatePayload method, indicating that a signature is expected. This modifies the behavior added in #1127, but not the spirit of what was requested in #1126, which is to support webhooks that don't have configured secrets. Specifically, this no longer allows signature checking to be skipped entirely, even for webhooks with a configured secret, simply by passing an empty secretToken to ValidatePayload. Fixes #2731
The problem is that as the authors of FWIW, even if I did make a call to
We are agreed on this point. i.e. everyone should use secrets, even in development. It therefore feels like we're bending over backwards too much for the case of a (development) mode where no secret is used. If the call to This rightly shifts the burden of working around this in cases where no secret is used onto the developer. In fact I'd argue that doing so will actually increase the likelihood that people will shift to using secrets. Right now, the pattern of allowing The message then shifts to become "even in development mode you should set a secret". Perhaps I'm missing something of the workflow/DX of this (development) mode where no secret is set. Can someone point me to an example of what requires people to not set a secret in such a mode? Why can they not just set a simple secret like |
Sure, I completely see where you're coming from. In some ways, this approaches a philosophical question of what the role of go-github is. In general, we've tried to simply provide an unopinionated, idiomatic Go library for the capabilities of the GitHub REST API. Maybe GitHub shouldn't allow creating webhooks without secrets, but since they do, I don't think it's unreasonable for the library to support that (and in this case, provide a helper function to validate the presence or absence of a payload signature, based on what the caller indicates is expected). There may be be cases where we have taken a more principled stance and not supported some capability of the GitHub API, but none immediately come to mind. So on this particular point, we just disagree. But I think it's a relatively small difference in the grand scheme of things. And I also think this function is in a much better spot thanks to this issue (pointing out the mis-feature of being able to skip signature checks altogether), so honestly thanks for brining it up! |
#1127 added support for calling
ValidatePayload
with anil
or emptysecretToken
slice. The justification for this change is explained in the current docs:I think this leaves
ValidatePayload
with dangerous default behaviour. Because now every caller of this function has to check that they have a non-nil
and non-emptysecretToken
slice if they want to validate a payload. If they don't, it's possible to accidentally call the function with anil
or empty slice (bad configuration, etc) and never know about it. This is not a safe default. Better would be to have the functionpanic
or return an error in casesecretToken
isnil
or empty - because such a value can never be used to validate a payload, which is obviously what the caller intended to do in calling the function.The same applies to
ValidatePayloadFromBody()
.I haven't looked at other functions/methods.
Returning to the goal of #1126, I would instead have pushed back and suggested that developers who are in development mode change their calling code to simply not call
ValidatePayload
when they detect they are in such a mode.The text was updated successfully, but these errors were encountered: