[GO] Play with the password mechanism of GitHub Webhook and Python

secret.png

What is this Secret field happy (゜ ∀ ゜)

I have a recent feeling that this has been entered. I will write down the process that I tried roughly. Please point out any mistakes.

What kind of function

In short, GitHub will send you the payload signature.

The result of HMAC (keyed hash) the sent JSON payload using this key It is a mechanism that inserts into the HTTP header of WebHook. Secret is not seen on the GitHub screen after input, and it does not appear raw in HTTP data after that, so that is also a little safe.

You can re-enter

I think this mechanism didn't exist in the past. Probably not right after the WebHook was renewed. When did you come in

Reference: http://blog.manaten.net/entry/573

Looking at the above page, I feel the significance of information preservation. There is no password field, I put it in the query string myself. It was a year ago.

What makes me happy

You can easily increase the safety level.

You can basically POST to the WebHook URL, and you cannot embed CSRF tokens. Every time I write @ csrf_exempt in Django, the SAN value goes down, but it can't be helped.

For the time being, WebHook's mouth seems to be able to loosely apply IP restrictions, so I will use it. Still, there are concerns that something will come in from the malicious GitHub project. It seems that all or a considerable amount of information sent can be disguised (although I haven't examined it).

So I actually wanted a key other than the URL. But I don't want to write the implementation by myself (the people on the above site write it by themselves, isn't it?)

What kind of behavior

When GitHub sends a WebHook, it converts the JSON payload string into a 40-character hash with HMAC + sha1 using key. So, when sending an HTTP POST, a string like `` `sha1 = dd671d65f5aee8c8aba748fd8f0143c10c5ba875``` will be inserted in the header. The server (yourself) will receive the payload and its "signature".

The recipient, that is, your server, can verify the signature by converting the JSON string sent using the common key into a hash with the same algorithm. If the signature is wrong, you can send a warning to the administrator because it is ok.

Maybe it's not too difficult if it's a scripting language with an OpenSSL wrapper, and since both HMAC and sha1 have normal algorithms, you can probably verify them in the shell (which means you don't use `` `sha1sum```. I won't try it, I'll never try it).

It seems that the library is used as it is even in the (apparently) Ruby implementation used by GitHub itself.

It's also in Python. A deliberate Python taste.

Let's use it with Python (+ Django)

In order to receive the JSON payload, prepare two types of saucers according to the Content-Type on the server side. This itself is implemented regardless of this story.

Also, the character string sent is pulled out via `` request.META.get ('HTTP_X_HUB_SIGNATURE') `.

If it is empty, there is no password. If it's not empty, pop the raw payload string into hmac / hashlib.sha1 and generate a keyed hash on your own to see if it's the same.

import hashlib
import hmac

...

    if content_type == 'application/json':
        payload = request.body
    else:
        payload = request.POST.get('payload')
    signature = request.META.get('HTTP_X_HUB_SIGNATURE')
    if signature:
        hasher = hmac.new(secret, payload, hashlib.sha1)
        logger.debug('Signature : {}'.format(signature))
        logger.debug('Calculated: sha1={}'.format(hasher.hexdigest()))

I feel that this is good because the calculation results match at hand.

However, I'm not sure if the encoding and line feed code always match every time. If you have any details, please comment.

bonus

I don't want to remember the raw key on the server side, but if you know an easy and good way, please let me know. I wonder if it's easy to save the serialized version with Django ...

Addendum: When testing with django.test.Client

If the payload itself is ready as a string, all you have to do is screw the above generated result into the header equivalent. In Django 1.6.5, you can incorporate it as follows.

        hasher = hmac.new('TestSecret', payload_str, hashlib.sha1)
        response = self.client.post(
            url, data={'payload': payload_str},
            HTTP_X_HUB_SIGNATURE='sha1={}'.format(hasher.hexdigest()))

It's django 1.6.5, but if you set "application / x-www-form-urlencoded" that can be selected on GitHub as content_type to Client, you will not be able to receive POST data with response.POST.get ('...'). There seems to be a problem. About content_type Let's make it possible to receive multipart / form-data on the server side as well. GitHub may change a lot soon.

Recommended Posts

Play with the password mechanism of GitHub Webhook and Python
Visualize the range of interpolation and extrapolation with python
Let's play with Python Receive and save / display the text of the input form
The story of Python and the story of NaN
Coexistence of Python2 and 3 with CircleCI (1.0)
I compared the speed of Hash with Topaz, Ruby and Python
[Required subject DI] Implement and understand the mechanism of DI with Go
Check the existence of the file with python
Play with 2016-Python
I replaced the numerical calculation of Python with Rust and compared the speed
Calculate the shortest route of a graph with Dijkstra's algorithm and Python
Get the number of articles accessed and likes with Qiita API + Python
Get and estimate the shape of the head using Dlib and OpenCV with python
I measured the speed of list comprehension, for and while with python2.7.
Prepare the execution environment of Python3 with Docker
Summary of the differences between PHP and Python
2016 The University of Tokyo Mathematics Solved with Python
[Note] Export the html of the site with python.
The answer of "1/2" is different between python2 and 3
Calculate the total number of combinations with python
Specifying the range of ruby and python arrays
Compare the speed of Python append and map
Implementation of TRIE tree with Python and LOUDS
Solving the Lorenz 96 model with Julia and Python
Archive and compress the entire directory with python
Convert the character code of the file with Python3
About the * (asterisk) argument of python (and itertools.starmap)
A discussion of the strengths and weaknesses of Python
[Python] Determine the type of iris with SVM
Example of reading and writing CSV with Python
Deep Learning from scratch The theory and implementation of deep learning learned with Python Chapter 3
Try out the touch of data-driven testing with Selenium Python Bindings and py.test
the zen of Python
Article that can be a human resource who understands and masters the mechanism of API (with Python code)
Extract the table of image files with OneDrive & Python
The story of Python without increment and decrement operators.
Learn Nim with Python (from the beginning of the year).
Play with the UI implementation of Pythonista3 [Super Super Introduction]
The process of installing Atom and getting Python running
Destroy the intermediate expression of the sweep method with Python
Python --Explanation and usage summary of the top 24 packages
Easy partial download of mp4 with python and youtube-dl!
Calculate the regression coefficient of simple regression analysis with python
Referencing and changing the upper bound of Python recursion
I checked out the versions of Blender and Python
Summary of the basic flow of machine learning with Python
Get the operation status of JR West with Python
Extract the band information of raster data with python
Comparison of CoffeeScript with JavaScript, Python and Ruby grammar
Version control of Node, Ruby and Python with anyenv
Build API server for checking the operation of front implementation with python3 and Flask
Extract images and tables from pdf with python to reduce the burden of reporting
I tried to compare the processing speed with dplyr of R and pandas of Python
I tried to find the entropy of the image with python
Try scraping the data of COVID-19 in Tokyo with Python
Encryption and decryption with Python
I tried "gamma correction" of the image with Python + OpenCV
Mechanism of pyenv and virtualenv
Towards the retirement of Python2
Python and hardware-Using RS232C with Python-
The story of implementing the popular Facebook Messenger Bot with python