I’m trying to better understand Activitypub and I understand that there’s a signature to avoid forgeries of known accounts.

However I’m having trouble understanding what prevents a malicious actor from sending a private spam message supposedly from a never before seen account name with valid generated key pair but for a domain they’ve never bought since there is no DNS lookup or test.

Thank you!

  • terribleplan@lemmy.nrd.li
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    To do the signature validation you need to know/trust the public key signing the incoming request (which will use the keyId in the signature to specify the key of the actor, usually a Person, that made the thing, when your server gets this comment the keyId will be https://lemmy.nrd.li/u/terribleplan#main-key). A good server will check that the keyId only differs from the actor of the object by having a fragment appended.

    Your server needs to fetch my Person object, of https://lemmy.nrd.li/u/terribleplan. If you load that with an Accept header of application/activity+json you get:

    {
        "@context": [
            "https://www.w3.org/ns/activitystreams",
            "https://w3id.org/security/v1",
            {
                "lemmy": "https://join-lemmy.org/ns#",
                "litepub": "http://litepub.social/ns#",
                "pt": "https://joinpeertube.org/ns#",
                "sc": "http://schema.org/",
                "ChatMessage": "litepub:ChatMessage",
                "commentsEnabled": "pt:commentsEnabled",
                "sensitive": "as:sensitive",
                "matrixUserId": "lemmy:matrixUserId",
                "postingRestrictedToMods": "lemmy:postingRestrictedToMods",
                "removeData": "lemmy:removeData",
                "stickied": "lemmy:stickied",
                "moderators": {
                    "@type": "@id",
                    "@id": "lemmy:moderators"
                },
                "expires": "as:endTime",
                "distinguished": "lemmy:distinguished",
                "language": "sc:inLanguage",
                "identifier": "sc:identifier"
            }
        ],
        "type": "Person",
        "id": "https://lemmy.nrd.li/u/terribleplan",
        "preferredUsername": "terribleplan",
        "inbox": "https://lemmy.nrd.li/u/terribleplan/inbox",
        "outbox": "https://lemmy.nrd.li/u/terribleplan/outbox",
        "publicKey": {
            "id": "https://lemmy.nrd.li/u/terribleplan#main-key",
            "owner": "https://lemmy.nrd.li/u/terribleplan",
            "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzX8XfO3F/nBKgST+Rqu8\noBxyE1GdvdXpYUYXq9OqwYEVIsE4Jth+aRzx4rSnotnMYyxbhBst3t77dSZAf7ir\nHjpdSoRYdZ0Ce3qJc4mpnctPtDSIjWl+fYwG9oPF51D8cwJewUejHcj6v6ud44Q5\nHbuiYqrMQo2YtWGKMAmjErE8cFinuNcpoNDCCzopCXWfpks48II6f4/aT/Kd66zo\niUYvBMrEmqWATZVbTwnh2MSwu7XTh8O5SlUeceb3LpC7dyCCpkVJU+DYDVqOfPBA\nSb+KmxqOVnewZor6zVDtfelXXx7Zikbff+IcUGbuiJRUlNsyqaq2kxJMZjO/UYCc\newIDAQAB\n-----END PUBLIC KEY-----\n"
        },
        "name": "terribleplan",
        "summary": "<p>DevOps as a profession and software development for fun. Admin of lemmy.nrd.li.</p>\n",
        "source": {
            "content": "DevOps as a profession and software development for fun. Admin of lemmy.nrd.li.",
            "mediaType": "text/markdown"
        },
        "icon": {
            "type": "Image",
            "url": "https://lemmy.nrd.li/pictrs/image/680ced6c-b461-4d7c-906a-9091268f6e7e.jpeg"
        },
        "endpoints": {
            "sharedInbox": "https://lemmy.nrd.li/inbox"
        },
        "published": "2023-06-10T16:10:13.859768+00:00"
    }
    

    You can see my Person object contains .publicKey.publicKeyPem, that is what your server will use (and store after fetching it once) to validate the incoming payload/header.

    • Wander@yiffit.netOP
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 year ago

      Ah, that makes sense. The server tries to retrieve the actor object from the actual url and would notice a discrepancy. That makes sense and is an easy way to implement validations.

      I was wondering if I could ask you something else related to activity pub since you seen knowledgeable in the matter. I’ve been going over these all day and haven’t been able to find a good answer:

      1. My understanding is that a create activity doesn’t need to have the content itself in the message since JSON-LD exposes the permanent uri in the id property and the receiving server can then make a subsequent request for the content.

      Is there a consensus on which approach is better and what would happen if the content field in a note is different from the content that would be fetched by a url?

      1. I’ve seen that groups are implemented by doing announces. In theory announces could be private based on the view permissions of the original activity. Does that mean that we could potentially have private Lemmy communities at some point?

      In that regard, I was wondering if it’s possible for an organization or group type actor to forward the activity not with announces but by simply delivering the content to the user’s inbox in a transparent manner, similar to an email distribution list.

      Thank you <3