Hello !
When someone connects to my instances communities, but from another instance, how do I know it’s no spoofing involved?
Cheers
Hello !
When someone connects to my instances communities, but from another instance, how do I know it’s no spoofing involved?
Cheers
Messages are sent with a digital signature that only the original instance could craft.
Having worked with lemmy_server code for months, I wouldn’t trust it in practice. Unless someone produces a pretty through test to validate that it actually works as intended when out-of-band data delivery attempts are made. And for discussion sake, I am assuming comment and posting “messages”, and not private messages… which is a whole different set of behaviors.
when a user homed on lemm.ee comments on a post where the community is hosted on lemmy.world, it would get delivered to lemmy.ml by lemmy.world, not the origin lemm.ee instance.
I don’t think the actual message carries a signature from the origin instance, in this case lemm.ee - I could be wrong, because it may not unpack and repackage it before forwarding to subscribed instance servers. But there are some very short timeouts on these signatures and HTTP connections, and I think it does unpackage it and repackage a public comment message.
I think lemmy.ml would need to go fetch the profile for the then unknown user to be able to get the display name and other details of the lemm.ee comment creator to display on the comment. The signature for the comment I think would actually only validate lemmy.world to lemmy.ml - and if lemmy.ml already has the profile of the lemm.ee user stored locally it may not verify it (and could be an entirely different install with the same username). But I don’t think many have ventured into study the code in these areas. The whole process hasn’t been examined that much and I wouldn’t be surprised at all if there are issues with post and comment getting dropped because servers aren’t all reachable at the right times for these steps.
Hello RoundSparrow, and again thank you for your help when I was in trouble setting up my little instance!
It runs well now :-)
Just as a backdrop I’m curious about how Lemmy works (I’m building a sharing protocol & implementation, decentralised, takedown safe, rugged, … It feels like how Lemmy is built on top of its protocol) and I love Lemmy and how it “federates” 💗 so I want to know more about it all.
When you say packages get forwarded to whatever instance wanted (if I understand correctly) you don’t “unpack” (e.g check if it’s a valid request) which seems logic, the end instances does do the security check right? I mean if the end instance doesn’t check, you checking won’t help them out.
But then again, if I understand you correctly, the trust is split in two; the poster from A posting on B, then B sending all its posts to C, D, E, …
Which would mean it’s enough to trust B to trust A. If you trust B enough :-)
Guess I’m off to learn Rust and try to compile all this :-)
Thanks again, and sorry for the ramblings. It’s late here and I have not very much time.
I personally would need to dig into testing and code again to give answers with confidence. What I’m trying to say more than anything is… don’t assume. The level of mistakes in Lemmy’s more technical back-end code are pretty high from my experience, especially when it comes to multiple servers involved (comment deletes not being sent to all servers was a situation I tracked down). What I do know is that there is very little written out there about people actually tearing it apart and showing what works… a lot of stuff gets logged in server logs as errors that almost nobody can explain. Either it’s mistakes in apub JSON or other non-lemmy servers, or older versions of Lemmy, etc.
the pack metaphor isn’t that great. But it is signed, and the receiving server checks a signature. But I really have not seen anyone discuss how those signatures are exchanged in the first place, and I’ve seen people say they re-installed their entire instance - which I assume generates a new set of signing keys for the same domain name… and I know Lemmy starts with 1 in index for post, comment, person - and would end up generating the same numbers for different content.
I haven’t seen much eye towards auditing any of this works, and if it even is a good design. Even 2 months ago there were some aggressive timeouts that were causing delivery to fail. And when something fails, the person who comments or posts doesn’t get notified…
There is some deep stuff in lemmy., every community has a private key/public key pair, as does each person - but I’m not even sure that is used at all and was an ambition. I rarely see the topic actually come up and I’ve been listening for this kind of deeper technical topics… and created !lemmyfederation@lemmy.ml to try and better organize it.
I’m pretty much rambling myself… my repeat point is: don’t assume. I would not describe Lemmy as battle-hardened against attacks or spoofing that someone can find to bypass the current logic.
Thanks again, I’m at a new job, it’s summertime, but soon I think I’ll dig into the whole compiling Lemmy thing checking out how it all works :-)
I’m a huge complexity & somehow network nerd so at least I’m going to see some interesting stuff and Rust seems to be quite abordable for an old-timer.
Okay so it’s the lemmt server running my instance that checks it is the right user. Do you know how it is done ?
I reread your post, so it’s a signature in the http call?
It’s a https certificate connected to the domain name of the instance.
Okay thank you very much!
Here’s quite a good overview. The short answer, I think, is that the signature is embedded into the JSON object representing the post / upvote / whatever, which then gets passed around server-to-server (and each server checks the signature against the original server’s TLS certificate). It’s not something you can get your head around just by asking a couple simple questions but it’s a pretty fascinating design when you get your head around it.
Ha ha yeah it’s not easy peasy when you start with these kind of things for sure, thanks for the link! It seems it shows the day to say stuff (and the pubkey embedded in the json) thanks again.
So if I want to validate a user outside of the Lemmy service (the one that runs in a docker on my lemmy-box), I “just” have to get the public key from the Lemmy database and validate the digest/signature?
Cheers!
You shouldn’t have to… as I understand it, if it’s showing up on your server, that means your server authenticated it. Given the general flakiness of all this software and Lemmy in particular, I wouldn’t put too much reliability on that, but that’s the theory.
If you do want to double-check it yourself, I know partially how to do it. You don’t have to get the key from the database; it’s probably simpler and safer to get it from your user’s JSON. Here’s a super-basic script to dump a fediverse endpoint’s contents:
import requests import json import sys def fetch_and_pretty_print(url, headers=None): # If headers are not provided, set default to fetch ActivityPub content if headers is None: headers = { 'Accept': 'application/activity+json', 'User-Agent': 'Fediverse dump tool via @mo_ztt@lemmy.world' } try: response = requests.get(url, headers=headers) response.raise_for_status() # Raise an exception for HTTP errors # Try to parse JSON and pretty print it parsed_json = response.json() print(json.dumps(parsed_json, indent=4, sort_keys=True)) except requests.RequestException as e: print(f"Error fetching the URL: {e}") except json.JSONDecodeError: print("Error decoding JSON.") if __name__ == '__main__': fetch_and_pretty_print(sys.argv[1])
If I want to validate your comment, I would start by getting your public key via your user’s endpoint on your home server. I could save that script up above as
fetch
, then runpython fetch https://lemmy.mindoki.com/u/Loulou
, and in among with a bunch of other stuff I would see:"publicKey": { "id": "https://lemmy.mindoki.com/u/Loulou#main-key", "owner": "https://lemmy.mindoki.com/u/Loulou", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArRwWZneP9efCrsymHDE2\nsJAHojjxE4A2Q3Hquwt7s/HPTAi3gKP7NKCRSH7XVPtGhieJdtDeoLMkitvZXCUX\nS1pZArTYihuLeOwbB+JrAHZpWr1sYpazspUPvl3MhDAOOCCAnSeqsMNPNd8QX1Tf\nN/3Bp4PRVmp9E968L61h93L5N3B7VxZ37kbzKFXrhmU6qFQbAoVQvHtojCD6WqR2\nMb84eJy5QBN+0SjvGR8LRE0iJZiwYvVXKNoEyOqr4Fw8YnELi3TYbfxX++0uXw97\ne+/rFgaa/QVCSopUbHkuX/ZfjzCdBAI+aqXsbmYLgdxdRDHur0k53aCh3u0t/IDL\nHQIDAQAB\n-----END PUBLIC KEY-----\n" },
I don’t know off the top of my head how you could navigate your way to the fediverse JSON for your comment, or how to verify its signature once you find it (I tried to get the post by dumping your user’s outbox and the lemmy_support community’s outbox, but neither of those worked the way I expected it to), but that all might be a helpful starting point. I know that according to the docs, anything that was created by your user and then federated is supposed to be signed with that key so that other servers can authenticate it.
It should be a signature that is sent together with the ActivityPub Object. Yes, if the signature doesn’t match, the content, whether a post, comment, favorite, upvote, etc… should be dropped.
Here is the source code of the library that lemmy uses to handle incoming objects and you can see that it does a call to verify the signature of the actor:
https://docs.rs/activitypub_federation/latest/src/activitypub_federation/actix_web/inbox.rs.html#18-54