Repository: buildbot/buildbot

Issue:
Use hmac.compare_digest in the GitHub webhook if possible
Currently buildbot uses naive `!=` to compare digests. 

https://github.com/buildbot/buildbot/blob/f522a22a88d6f2d39e8ff1afe639dc7ff6ef4a39/master/buildbot/www/hooks/github.py#L117-L120

I propose to use hmac.compare_digest() if possible. For example: (not tested yet)

```Python
def _cmp(a, b):
    try:
        # try the more secure compare_digest() first
        from hmac import compare_digest
        return compare_digest(a, b)
    except ImportError:
        # and fallback to the insecure simple comparison otherwise
        return a == b

if not _cmp(mac.hexdigest(), hexdigest):
    raise ValueError('Hash mismatch') 
```

If this sounds a good idea, I'll try to open a pull request.

BTW, HMAC verification has been implemented long time ago (https://github.com/buildbot/buildbot/commit/baf1f47a5521dae8752cc4a236cbf35ff4db0e18), but the doc implies it's missing (https://github.com/buildbot/buildbot/blob/master/master/docs/manual/cfg-wwwhooks.rst)

> Patches are welcome to implement: https://developer.github.com/webhooks/securing/

EDIT: a grammar fix


Discussion:
please go ahead and submit the fix and doc fix

On Thu, Jun 28, 2018 at 7:24 PM Chih-Hsuan Yen <notifications@github.com>
wrote:

> Currently buildbot uses naive != to compare digests.
>
>
> https://github.com/buildbot/buildbot/blob/f522a22a88d6f2d39e8ff1afe639dc7ff6ef4a39/master/buildbot/www/hooks/github.py#L117-L120
>
> I proposed to use hmac.compare_digest() if possible. For example: (not
> tested yet)
>
> def _cmp(a, b):
>     try:
>         # try the more secure compare_digest() first
>         from hmac import compare_digest
>         return compare_digest(a, b)
>     except ImportError:
>         # and fallback to the insecure simple comparison otherwise
>         return a == b
> if not _cmp(mac.hexdigest(), hexdigest):
>     raise ValueError('Hash mismatch')
>
> If this sounds a good idea, I'll try to open a pull request.
>
> BTW, HMAC verification has been implemented long time ago (baf1f47
> <https://github.com/buildbot/buildbot/commit/baf1f47a5521dae8752cc4a236cbf35ff4db0e18>),
> but the doc implies it's missing (
> https://github.com/buildbot/buildbot/blob/master/master/docs/manual/cfg-wwwhooks.rst
> )
>
> Patches are welcome to implement:
> https://developer.github.com/webhooks/securing/
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/buildbot/buildbot/issues/4180>, or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAGtI11mZB2Hqt00rQbDeqMZzq-4YgwKks5uBRE7gaJpZM4U7xw_>
> .
>
--


Resolving patch:
diff --git a/master/buildbot/www/hooks/github.py b/master/buildbot/www/hooks/github.py
--- a/master/buildbot/www/hooks/github.py
+++ b/master/buildbot/www/hooks/github.py
@@ -114,9 +114,17 @@ def _get_payload(self, request):
             mac = hmac.new(unicode2bytes(self._secret),
                            msg=unicode2bytes(content),
                            digestmod=sha1)
-            # NOTE: hmac.compare_digest should be used, but it's only available
-            # starting Python 2.7.7
-            if mac.hexdigest() != hexdigest:
+
+            def _cmp(a, b):
+                try:
+                    # try the more secure compare_digest() first
+                    from hmac import compare_digest
+                    return compare_digest(a, b)
+                except ImportError:  # pragma: no cover
+                    # and fallback to the insecure simple comparison otherwise
+                    return a == b
+
+            if not _cmp(bytes2unicode(mac.hexdigest()), hexdigest):
                 raise ValueError('Hash mismatch')
 
         content_type = request.getHeader(b'Content-Type')


Test patch: