web-dev-qa-db-ja.com

HMAC-SHA512とPOSTリクエストライブラリを使用してPythonリクエストに署名するにはどうすればよいですか?

私はPythonを使用して、暗号通貨取引所poloniex.comで取引APIにアクセスしようとしています。これを行うには、次の処方に従う必要があります。

Trading APIへのすべての呼び出しはHTTP POST to https://poloniex.com/tradingApi を介して送信され、次のヘッダーを含む必要があります:

キー-APIキー。
署名-クエリのPOST HMAC-SHA512メソッドに従ってキーの「秘密」によって署名されたデータ。

さらに、すべてのクエリには「ノンス」POSTパラメータが含まれている必要があります。ノンスパラメータは整数であり、以前に使用されたノンスより常に大きい必要があります。

これが私がこれまで持ってきたものです。私の現在の問題は、POST URLをコンパイルして、最初に不完全な要求を送信せずに署名できるようにする方法がわからないことです。これは明らかに機能しません。

import requests
import hmac
import hashlib
import time

headers = { 'nonce': '',
            'Key' : 'myKey',
            'Sign': '',}
payload = { 'command': 'returnCompleteBalances',
            'account': 'all'}
secret = 'mySecret'

headers['nonce'] = int(time.time())
response = requests.post( 'https://poloniex.com/tradingApi', params= payload, headers= headers )
headers['Sign'] = hmac.new( secret, response.url, hashlib.sha512)
12
Werhli

preparedrequest ;を作成します。本文が作成された後で、ヘッダーを追加できます。

_import requests
import hmac
import hashlib


request = requests.Request(
    'POST', 'https://poloniex.com/tradingApi',
    data=payload, headers=headers)
prepped = request.prepare()
signature = hmac.new(secret, prepped.body, digestmod=hashlib.sha512)
prepped.headers['Sign'] = signature.hexdigest()

with requests.Session() as session:
    response = session.send(prepped)
_

params引数をdataに変更しました。 POSTリクエストの場合、URLではなく、本文でパラメータを送信するのが通例です。

Nonceには、再起動が影響しないように、現在の時刻からシードされた itertools.count() object を使用します。 Poloniex APIドキュメント (質問で引用したもの)によると、ナンスはPOSTボディの一部であり、ヘッダーではないので、payload辞書:

_from itertools import count
import time

# store as a global variable
NONCE_COUNTER = count(int(time.time() * 1000))

# then every time you create a request
payload['nonce'] = next(NONCE_COUNTER)
_

int(time.time())を使用すると、1秒間に複数のリクエストを作成した場合に同じ番号が再利用されます。 Poloniexによって提供されるサンプルコードint(time.time()*1000)を使用して、代わりにマイクロ秒ごとにリクエストを作成できるようにしますが、独自の単調に増加するカウンターを使用します(time.time()からシード) )ははるかに堅牢です。

ダイジェスト署名プロセスを カスタム認証オブジェクト にカプセル化することもできます。そのようなオブジェクトは、準備の最後のステップとして準備済みリクエストで渡されます。

_import hmac
import hashlib

class BodyDigestSignature(object):
    def __init__(self, secret, header='Sign', algorithm=hashlib.sha512):
        self.secret = secret
        self.header = header
        self.algorithm = algorithm

    def __call__(self, request):
        body = request.body
        if not isinstance(body, bytes):   # Python 3
            body = body.encode('latin1')  # standard encoding for HTTP
        signature = hmac.new(self.secret, body, digestmod=self.algorithm)
        request.headers[self.header] = signature.hexdigest()
        return request
_

これをrequests呼び出しで使用します。

_response = requests.post(
    'https://poloniex.com/tradingApi',
    data=payload, headers=headers, auth=BodyDigestSignature(secret))
_

渡される引数は、HMACダイジェストで使用される秘密です。別のヘッダー名を渡すこともできます。

21
Martijn Pieters