pyauth / requests-http-signature Goto Github PK
View Code? Open in Web Editor NEWA Requests auth module for the IETF HTTP Message Signatures draft standard
Home Page: https://pyauth.github.io/requests-http-signature/
License: Apache License 2.0
A Requests auth module for the IETF HTTP Message Signatures draft standard
Home Page: https://pyauth.github.io/requests-http-signature/
License: Apache License 2.0
The add_digest
method modifies self.headers
in-place making this class unsuitable for reuse across multiple requests.
Currently, it just splits on commas. However, I believe commas are allowed in eg. the keyId
parameter if the value is enclosed in quotes.
Example:
Authentication: keyId="test,key",signature="...",algorithm="..."
Hi, I'm @msporny, primary author of the HTTP Signatures specification at IETF for many years now. You've implemented some variation of that specification.
I need your help to move that specification towards a global standard at IETF. Hearing from implementers, such as you, is a big part of determining if the work toward a global standard should proceed. The IETF HTTP Working Group is determining whether the work should proceed right now. This is very good news, because the European Banking API community, W3C DID Working Group, W3C Credentials Community Group and other standards setting organizations depend on implementations standardizing on a way to do HTTP Signatures.
The deadline for noting your support is Jan 31st 2020 (in ~10 days).
Here's where you can make a difference...
Here is the IETF HTTP WG Call for Adoption:
https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0002.html
To note your support of the specification:
For an example of the type of email you could write, see this:
https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0018.html
Thanks a ton for supporting the specification through your implementation. I hope you consider helping us take the specification across the goal line by voicing your support in the IETF HTTP Working Group!
Hi and thanks for working on this library!
There's a couple changes that have been merged in since the 0.2.0 release that I'd like to make use of in a project of mine.
Would it be possible to push a new release to pypi that has those changes?
Thanks again!
Hello!
I am working on a project involving requests-oauthlib and this library. And i have run into some bugs/issues. For these i have provided possible fixes that i am willing to make a PR for after having recieved feedback.
1 An empty body leads to error:
File "[omitted]/python3.7/site-packages/requests/structures.py", line 54, in __getitem__ return self._store[key.lower()][1] KeyError: 'digest'
My current workaround: Override add_digest
, and build in check:
class MyHTTPSignatureAuth(HTTPSignatureAuth):
def add_digest(self, request):
if not request.body:
# Since the message body (payload) is empty, the digest is defaulted to the hash256 of an empty body.
request.headers["Digest"] = "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
else:
return super(MyHTTPSignatureAuth, self).__call__(request)
Suggested change: Build check into the actual code
2 Incorrect body encoding leads to error:
File "[omitted]/python3.7/site-packages/requests_http_signature/__init__.py", line 73, in add_digest digest = self.hasher_constructor(request.body).digest() TypeError: Unicode-objects must be encoded before hashing
My current workaround: Override add_digest
, and encode to utf-8:
class MyHTTPSignatureAuth(HTTPSignatureAuth):
def add_digest(self, request):
if request.body:
request.body=request.body.encode('utf-8')
super(MyHTTPSignatureAuth, self).add_digest(request)
Suggested change: This workaround probably wouldn't translate into a fix directly as utf-8
is not always the desired encoding (i think). Though i dont understand enough about the crypto and http standard to be sure of this. If multiple encodings should be supported, the option should be added somewhere, if not, we should always convert to utf-8
Note: In python3 everything is unicode thus this error will happen by default, always.
3 Doesn't play nice with token authorization
This auth lib works when requesting auth tokens because is sets the Authorization
header. However when signing subsequent messages, the Authorization
header should be the token, and the Signature should be specified in the Signature
header
My current workaround: Override __call__
, and build check for preexisting Authorization
field:
class MyHTTPSignatureAuth(HTTPSignatureAuth):
def __call__(self, request):
if "Authorization" in request.headers:
auth = request.headers["Authorization"]
req = super(MyHTTPSignatureAuth, self).__call__(request)
req.headers["Signature"]=req.headers["Authorization"].split(' ', 1)[1]
req.headers["Authorization"]=auth
return req
else:
return super(MyHTTPSignatureAuth, self).__call__(request)
Suggested change: Unclear. I don't know if adding the Signature
field even is the intended purpose of the library. I don't know when the Signature
header should be used over the Authorization
header. For a fix i would probably lean towards providing an option in the constructor to set Signature
instead of Authorization
, or maybe go with the dirty code in the work around if it doen't cause any issues.
Any thoughts on these changes? Should i implement them in a PR?
P.s: here is the whole class i am using at the moment:
class MyHTTPSignatureAuth(HTTPSignatureAuth):
def __call__(self, request):
if "Authorization" in request.headers:
auth = request.headers["Authorization"]
req = super(MyHTTPSignatureAuth, self).__call__(request)
req.headers["Signature"]=req.headers["Authorization"].split(' ', 1)[1]
req.headers["Authorization"]=auth
return req
else:
return super(MyHTTPSignatureAuth, self).__call__(request)
def add_digest(self, request):
if request.body:
request.body=request.body.encode('utf-8')
super(MyHTTPSignatureAuth, self).add_digest(request)
else:
super(MyHTTPSignatureAuth, self).add_digest(request)
return
# Since the message body (payload) is empty, the digest is defaulted to the hash256 of an empty body.
request.headers["Digest"] = "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
7.23. Non-List Field Values
When an HTTP field occurs multiple times in a single message, these
values need to be combined into a single one-line string value to be
included in the HTTP signature base, as described in Section 2.4.
Not all HTTP fields can be combined into a single value in this way
and still be a valid value for the field. For the purposes of
generating the signature base, the message component value is never
meant to be read back out of the signature base string or used in the
application. Therefore it is considered best practice to treat the
signature base generation algorithm separately from processing the
field values by the application, particularly for fields that are
known to have this property. If the field values that are being
signed do not validate, the signed message should also be rejected.
If an HTTP field allows for unquoted commas within its values,
combining multiple field values can lead to a situation where two
semantically different messages produce the same line in a signature
base. For example, take the following hypothetical header field with
an internal comma in its syntax, here used to define two separate
lists of values:
Example-Header: value, with, lots
Example-Header: of, commas
For this header field, sending all of these values as a single field
value results in a single list of values:
Example-Header: value, with, lots, of, commas
Both of these messages would create the following line in the
signature base:
"example-header": value, with, lots, of, commas
Since two semantically distinct inputs can create the same output in
the signature base, special care has to be taken when handling such
values.
Specifically, the Set-Cookie field [COOKIE] defines an internal
syntax that does not conform to the List syntax in
[STRUCTURED-FIELDS]. In particular some portions allow unquoted
commas, and the field is typically sent as multiple separate field
lines with distinct values when sending multiple cookies. When
multiple Set-Cookie fields are sent in the same message, it is not
generally possible to combine these into a single line and be able to
parse and use the results, as discussed in [HTTP], Section 5.3.
Therefore, all the cookies need to be processed from their separate
header values, without being combined, while the signature base needs
to be processed from the special combined value generated solely for
this purpose. If the cookie value is invalid, the signed message
ought to be rejected as this is a possible padding attack as
described in Section 7.24.
To deal with this, an application can choose to limit signing of
problematic fields like Set-Cookie, such as including the field in a
signature only when a single field value is present and the results
would be unambiguous. Similar caution needs to be taken with all
fields that could have non-deterministic mappings into the signature
base. Signers can also make use of the bs parameter to armor such
fields, as described in Section 2.1.3.
7.24. Padding Attacks with Multiple Field Values
Since HTTP field values need to be combined in a single string value
to be included in the HTTP signature base, as described in
Section 2.4, it is possible for an attacker to inject an additional
value for a given field and add this to the signature base of the
verifier.
In most circumstances, this causes the signature validation to fail
as expected, since the new signature base value will not match the
one used by the signer to create the signature. However, it is
theoretically possible for the attacker to inject both a garbage
value to a field and a desired value to another field in order to
force a particular input. This is a variation of the collision
attack described in Section 7.5, where the attacker accomplishes
their change in the message by adding to existing field values.
To counter this, an application needs to validate the content of the
fields covered in the signature in addition to ensuring that the
signature itself validates. With such protections, the attacker's
padding attack would be rejected by the field value processor, even
in the case where the attacker could force a signature collision.
TypeError: key: expected bytes or bytearray, but got 'str'
Hi, thanks a lot for writing this library. I'm trying to setup HTTP signatures using RSA but I'm struggling to get it working. Could you please add an example of key_resolver()
with RSA in the README?
Thank you!
There's currently no way to require that certain headers are present in the signature, which is something all users should be doing to prevent clients from sending requests without any headers included in the signature.
Hello, I am getting the following warning:
requests_http_signature/__init__.py:25: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead.
signer = key.signer(padding=self.PKCS1v15(), algorithm=hasher)
I happened in the following code:
with open('certs/example_client_signing.key', 'rb') as fh:
auth=MyHTTPSignatureAuth(algorithm="rsa-sha256", headers=[ '(request-target)', 'date', 'digest' ], key=fh.read(), key_id=client_id)
i am using Python 3.5.3
Hi, and thank you for working on this library.
I was wondering, since the current release on pypi is 0.1.0 (from 2018), if it was possible to publish even a minor release update in order to get the package on pypi up to date with the last changes. Thank you.
HTTPX tries to be compatible with the requests package, including the use of callables for custom authentication. However, it is incompatible with requests_http_signature. When trying to sign a request, this is the error: AttributeError: 'Request' object has no attribute 'body'
requests_http_signature expects the body
attribute here, but the Request object does not have the attribute because it is called content
.
What I don't understand is that the Request object of the Requests library also seems to have no attribute called body
. Why does it work here then?
Hi I'm just trying to get started with this library, thanks much for it. Noticed that this link in README.rst takes me to an empty repo:
https://github.com/pyauth/flask-http-signature
I don't know your plans for that repo, just wanted to check if you might want to add some text here?
When using host
in headers=
with HTTPSignatureAuth, the signature does not validate.
Example:
headers=[ '(request-target)', 'date', 'digest' ]
headers=[ '(request-target)', 'host', 'date', 'digest' ]
I cannot test HTTPSignatureHeaderAuth
because there is not verify
method available.
https://stackoverflow.com/questions/1273211/disable-assertions-in-python
I can help to send an MR to remove assert and replaced with raising exception if it makes sense to remove assert for verification.
The class HTTPSignatureHeaderAuth
inherits the method verify()
that uses the default scheme="Authorization"
. It would be nice to override this method such that scheme="Signature"
is set automatically:
class HTTPSignatureHeaderAuth(HTTPSignatureAuth):
def verify(self, request, key_resolver):
return super().verify(request, key_resolver, scheme="Signature")
The digest header is validated if the client chooses to include it, but the verify method does not require it, and even when it is present, there's nothing to check that the digest actually matches the body of the request.
Currently the docs state that in order to instantiate an HTTPSignatureAuth
object an algorithm
argument has to be passed to the constructor. In v0.3.0 the argument was renamed to signature_algorithm
but it wasn't updated in the README.rst file
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.