如何安全地查看 Django REST 框架身份验证中的请求正文?

Dav*_*uth 6 python django python-2.7 django-rest-framework

我已经实现了一个网络钩子。调用者提供共享秘密。它们连接请求 URL 和正文,使用密钥对其进行签名,并在标头中提供签名。为了验证签名,我需要重复该过程并将我获得的签名与调用者获得的签名进行比较。

我正在使用 Django REST 框架。我正在检查自定义中的签名Authentication。框架以请求作为参数来调用Authentication的方法。authenticate我可以从 获取请求正文request.stream.read()。但是,这会消耗流,从而阻止框架为我解析它:当框架调用视图时,请求没有data像通常那样的属性。

request.stream不允许我这样做seek(0)。该请求不允许我用倒带流(例如StringIO. 我当前的解决方法是将主体存储在视图中request.auth并自己在视图中解析它,这有效但很丑陋。

有没有办法在 中安全地访问请求正文Authentication

这是有效的版本:

myapp/authentications.py

import hmac
from hashlib import sha1
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

class WebhookAuthentication(BaseAuthentication):
    def authenticate(self, request):
        actual_signature = request.META['X-Vendor-Signature']
        body, expected_signature = self.expected_signature(request)
        if actual_signature != expected_signature:
            raise AuthenticationFailed("Request X-Vendor-Signature did not match expected signature")
        return None, body  # Hack: preserve the body in request.auth

    def expected_signature(self, request):
        body = request.stream.read()
        raw = request.build_absolute_uri(request.META['PATH_INFO']) + body
        signature = hmac.new("the shared secret", raw, sha1).digest().encode("base64")
        return body, signature
Run Code Online (Sandbox Code Playgroud)

myapp/views.py

import json
from rest_framework.views import APIView    
from serializers import SomeSerializer
from myapp.authentications import WebhookAuthentication

class SomeView(APIView):
    authentication_classes = (WebhookAuthentication,)
    permission_classes = ()

    def post(self, request, _=None):
        data = json.loads(request.auth)  # Hack: get the body from where we stashed it
        serializer = SomeSerializer(data=data)  # I'd like to be able to use request.data here
        # Use the serializer ...
Run Code Online (Sandbox Code Playgroud)

我怎样才能比黑客做得更好?