Skip to content

Commit

Permalink
Add request verification to the webhook
Browse files Browse the repository at this point in the history
If the request is not sent from Github, service will be return the 403
status code. The verify is performed using the `X-Hub-Signature-256` key
in the request headers [1].

[1] tarantool/security#124
  • Loading branch information
Oleg Chaplashkin authored and ylobankov committed May 16, 2023
1 parent 32a32f1 commit 59c11dd
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ docker build -t docbot .
Then run it like this:

```sh
docker run -d -p5000:5000 -e GITHUB_TOKEN=<token> --name docbot docbot
docker run -d -p5000:5000 -e GITHUB_TOKEN=<token> -e GITHUB_SIGN_KEY=<sign_key> --name docbot docbot
```

To check that it works try to get `localhost:5000` - it will print the
Expand Down
8 changes: 7 additions & 1 deletion docbot/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

from elasticapm.contrib.flask import ElasticAPM
from prometheus_flask_exporter import PrometheusMetrics
from flask import Flask, request
from flask import Flask, Response, request

from .handlers import webhook_handler, list_events_handler
from .logging_config import LOGGING_CONFIG
from .utils import is_verified_signature


logging.config.dictConfig(LOGGING_CONFIG)
Expand Down Expand Up @@ -34,6 +35,11 @@ def index() -> str:
labels={'event': lambda: request.headers.get('X-GitHub-Event', None)}
)
def webhook() -> str:
if not is_verified_signature(
request.data,
request.headers.get('X-Hub-Signature-256', None)
):
return Response(status=403)
data: dict = request.json
event: str = request.headers.get('X-GitHub-Event')
extra = {
Expand Down
2 changes: 2 additions & 0 deletions docbot/settings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import os

token = os.environ.get('GITHUB_TOKEN')
github_signature = os.environ.get('GITHUB_SIGN_KEY')
assert token is not None
assert github_signature is not None
doc_requests = [' document\r\n', ' document\n']
bot_name = '@TarantoolBot'
title_header = 'Title:'
Expand Down
23 changes: 23 additions & 0 deletions docbot/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import datetime
import hashlib
import hmac

from . import settings

Expand All @@ -16,3 +18,24 @@ def create_event(author, action, body):
last_events.append(result)
if len(last_events) > settings.LAST_EVENTS_SIZE:
last_events.pop(0)

def is_verified_signature(body, signature):
"""Verify that the payload was sent from GitHub by validating SHA256.
Returns True if the request is authorized, otherwise False.
Args:
body: original request body to verify
signature: header received from GitHub
"""
if not signature:
return False
hash_object = hmac.new(
settings.github_signature.encode('utf-8'),
msg=body,
digestmod=hashlib.sha256
)
expected_signature = "sha256=" + hash_object.hexdigest()
if not hmac.compare_digest(expected_signature, signature):
return False
return True

0 comments on commit 59c11dd

Please sign in to comment.