GNU social JP
  • FAQ
  • Login
GNU social JPは日本のGNU socialサーバーです。
Usage/ToS/admin/test/Pleroma FE
  • Public

    • Public
    • Network
    • Groups
    • Featured
    • Popular
    • People

Embed Notice

HTML Code

Corresponding Notice

  1. Embed this notice
    Terence Eden’s Blog (blog@shkspr.mobi)'s status on Tuesday, 27-Feb-2024 07:09:36 JSTTerence Eden’s BlogTerence Eden’s Blog

    HTTP Signature Infinite Loop?
    https://shkspr.mobi/blog/2024/02/http-signature-infinite-loop/

    I'm trying to get my head round HTTP Signatures as they're used extensively in the Fediverse.

    Conceptually, they're relatively straightforward.

    You send me a normal HTTP request. For example, you want to POST something to https://example.com/data

    You send me these headers:

    POST /dataHost: example.comDate: Sat, 24 Feb 2024 14:43:48 GMTAccept-Encoding: gzipDigest: SHA-256=aaC57TDzM0Wq+50We2TkCsdMDvdqON92edg7KI+Hk8M=Content-Type: application/activity+jsonSignature: keyId="https://your_website.biz/publicKey",algorithm="rsa-sha256",headers="(request-target) host date digest content-type",signature="JGQ53kEoIiMWRp9By9jajVGCOCu4n7XBeiA1uY5xLcnAxL2Y1GIgU/...=="Connection: Keep-AliveContent-Length: 751

    In order to verify the contents of the message, I need to do three things:

    1. Check the SHA-256 hash of the message matches the content of the "Digest" header.
    2. Check the timestamp is somewhat fresh.
    3. Check the signature matches.

    The first is simple: base64_encode( hash( "sha256", $request_body, true ) ).
    The second is a matter of opinion. I might be happy to receive messages from the distant past or far in the future. For the sake of a little clock drift, let's allow 60 seconds either way.
    The third gets complicated.

    First, I need to get the public key published at keyId="https://your_website.biz/publicKey".

    Next, I need to know which algorithm is being used to sign the headers: algorithm="rsa-sha256"

    Then, I need to know which headers - and in what order - are being signed: headers="(request-target) host date digest content-type"

    So I create a string using the received details which matches those headers in that specific order:

    (request-target) POST /dataHost: example.comDate: Sat, 24 Feb 2024 14:43:48 GMTDigest: SHA-256=aaC57TDzM0Wq+50We2TkCsdMDvdqON92edg7KI+Hk8M=Content-Type: application/activity+json

    I can verify if the signature - signature="JGQ53kEoIiMWRp9By9jajVGCOCu4n7XBeiA1uY5xLcnAxL2Y1GIgU/...==" matches by:

    openssl_verify( $headersString, $signature, $publicKey, $algorithm);

    If that's TRUE then all is well.

    But can you spot the implicit problem?

    How do I get your server's public key?

    I just GET https://your_website.biz/publicKey - but if your server uses something like Authorised Fetch then I have to sign my request to you.

    Which means your server will need to validate my signature by obtaining my public key. Which it will get by signing a request and sending it to me. Which, before I return my public key, I will need to validate your signature by obtaining your public key. Which I will get by signing a request... and so on.

    This deadlock loop is documented. The usual way around it is either for the sending server to use an instance-specific signature which can be retrieved by an unsigned request, or to allow any unsigned request to access a user's public key.

    I get why things happen this way - I just wish it were easier to implement!

    https://shkspr.mobi/blog/2024/02/http-signature-infinite-loop/

    #ActivityPub #CyberSecurity #encryption #fediverse #http

    In conversationabout a year ago from shkspr.mobipermalink
  • Help
  • About
  • FAQ
  • TOS
  • Privacy
  • Source
  • Version
  • Contact

GNU social JP is a social network, courtesy of GNU social JP管理人. It runs on GNU social, version 2.0.2-dev, available under the GNU Affero General Public License.

Creative Commons Attribution 3.0 All GNU social JP content and data are available under the Creative Commons Attribution 3.0 license.