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.
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.
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.
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?)
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.
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.
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 ...
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