【问题标题】:Inconsistent SignatureDoesNotMatch Amazon S3 with django-pipeline, s3boto and storages不一致的 SignatureDoesNotMatch Amazon S3 与 django-pipeline、s3boto 和存储
【发布时间】:2012-08-02 23:14:54
【问题描述】:

我有 2 个由 django-pipeline 和 s3boto 编译的文件:master.css 和 master.js。它们在我的存储桶中设置为“公共”。但是,当我访问它们时,有时会提供 master.css,有时会出现 SignatureDoesNotMatch 错误。与 master.js 相同。这不会在 Chrome 上发生。我可能会错过什么?

编辑:现在也发生在 Chrome 上。

【问题讨论】:

    标签: python django amazon-s3 boto django-storage


    【解决方案1】:

    我也遇到过... 花了几个小时才找到,但我最终弄明白了。 事实证明,如果正确的签名是:

    ssCNsAOxLf5vA80ldAI3M0CU2%2Bw=

    那么 AWS 将不接受:

    ssCNsAOxLf5vA80ldAI3M0CU2+w=

    唯一的区别是将 %2B 翻译成 '+'。

    S3BotoStorage 实际上正确生成了它,但编码发生在 url 方法的最后一行的 CachedFilesMixin 上 (return unquote(final_url))。 为了修复它,我派生了一个新的 CachedFilesMixin 来撤消“损坏”(我应该提一下,我不知道为什么这个取消引用首先存在,所以撤消它可能会导致其他问题)

    class MyCachedFilesMixin(CachedFilesMixin):
    def url(self, *a, **kw):
        s = super(MyCachedFilesMixin, self).url(*a, **kw)
        if isinstance(s, unicode):
            s = s.encode('utf-8', 'ignore')
        scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
        path = urllib.quote(path, '/%')
        qs = urllib.quote_plus(qs, ':&=')
        return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))
    

    我在哪里使用了我找到的代码here

    希望这会有所帮助...

    【讨论】:

    • 我会尝试应用它,但您能否针对此问题验证此修改:stackoverflow.com/questions/12006894/…
    • 成功了。但是,正如上面链接的那样,boto 可能没有问题,而且我当然不想在每次我想将 boto 用于项目时都应用这个补丁。你能看看这个问题,看看你想出了什么吗?谢谢!
    • boto 的问题在于它不应该生成带有“空格”的签名并将其编码为“+”号。
    • 我不认为问题出在 boto,它似乎产生了正确的签名。问题出在 django 的 CachedFilesMixin 中,它将 %2B 转换为“+”。我在 Django 中有一个拉取请求,以删除 CachedFilesMixin.url 末尾的取消引用调用
    • @idnzalz 关心链接到拉取请求?我很想知道这是否成功。
    【解决方案2】:

    在使用 S3 签名 URL 和 python 请求 HTTP 库下载文件时,我遇到了导致 SignatureDoesNotMatch 错误的类似问题。

    我的问题最终变成了一个糟糕的内容类型。 AWS 上 Authenticating REST Requests 上的文档帮助我弄清楚了,并提供了 Python 示例。

    【讨论】:

    • 我正在发送一个InMemoryUploadedFile 文件,但忘记设置内容类型。正确设置内容类型后,一切正常!感谢您的提示。
    【解决方案3】:

    我为此苦苦挣扎了一段时间,我不喜欢搞砸 CachedFilesMixin 的想法(对我来说似乎有点矫枉过正)。

    在 django 平台发布适当的修复程序之前,我发现引用签名两次是一个不错的选择。我知道它不漂亮,但它很有效而且很简单。

    所以你只需要这样做:

    signature = urllib.quote_plus(signature.strip())
    signature = urllib.quote_plus(signature.strip())
    

    希望对你有帮助!

    【讨论】:

      【解决方案4】:

      这篇关于 Flask 的文章是获得正确签名的好资源:https://devcenter.heroku.com/articles/s3-upload-python

      @app.route('/sign_s3/')
      def sign_s3():
          AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID')       
          AWS_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
          S3_BUCKET = os.environ.get('S3_BUCKET')
      
          object_name = request.args.get('s3_object_name')
          mime_type = request.args.get('s3_object_type')
      
          expires = int(time.time()+10)
          amz_headers = "x-amz-acl:public-read"
      
          put_request = "PUT\n\n%s\n%d\n%s\n/%s/%s" % (mime_type, expires, amz_headers, S3_BUCKET, object_name)
      
          signature = base64.encodestring(hmac.new(AWS_SECRET_KEY,put_request, sha).digest())
          signature = urllib.quote_plus(signature.strip())
      
          url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, object_name)
      
          return json.dumps({
              'signed_request': '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature),
               'url': url
          })
      

      【讨论】:

        【解决方案5】:

        对我来说简单的解决方法是生成一个仅包含字母数字字符的新访问密钥(即没有 AWS 有时会添加到密钥中的特殊字符,例如“/”、“+”等)。

        【讨论】:

          猜你喜欢
          • 2012-03-25
          • 1970-01-01
          • 2012-05-04
          • 2012-08-02
          • 1970-01-01
          • 1970-01-01
          • 2021-12-04
          • 1970-01-01
          • 2013-01-18
          相关资源
          最近更新 更多