A few observations and concerns about general security defaults as well as network traffic encryption.
IPFS Directory
By default, ipfs init creates a folder for all ipfs settings and storage at ~/.ipfs … This is fine, and works well as a basic default location for most general purposes. The permissions on the directory are set such that all users on a multiuser OS have read access. Again, this is a fairly standard default setting for most *nix systems.
However, there are significant security issues with allowing all users read access to the ipfs directory. A saner default would be to mimic ssh and set the directory to 700 permissions, xrw for the owner and none for everyone else. This change to the default init would ensure that the node’s private key is not readable by other non-root system users.
swarm keys
Private IPFS swarm keys don’t seem to have any checks for appropriate filesystem permissions. As with the IPFS Directory permissions, private network swarm keys would probably be a little safer if the daemon would reject any keys that don’t have 600 or 400 permissions.
IPFS traffic cover
Private IPFS networks using swarm keys seem to authenticate using a swarm key derived one-time use session key. This may or may not work well against a replay attack. I haven’t tested it and probably don’t have time to go through the go code base since I’m not familiar with the go language. However, it seems possible at first look for an attacker to sniff the authentication and grab the session key. I would feel much better if the traffic was encrypted via some opportunistic cryptographic function. At the moment, I’m utilizing an ssh reverse tunnel for traffic cover. It would be helpful if IPFS included the ability to create secure tunnels to private nodes on WAN addresses before the authentication credentials are exchanged.
Perhaps I don’t know what I’m doing…
If this is the case, please correct my misunderstanding.
the config and datastore_spec files have 0600 perms by default. The keystore folder has 0700 perms.
I suggest opening an issue about this in go-ipfs. Since the creation of the private swarm key is something that the user does, IPFS does not check permissions. But it would be good if it did (and probably easy to do).
Please don’t presume things and say that it “seems possible”. Private networks used a stream-cipher based on salsa20, using the preshared keys. There is no concept of session or authentication because there is no key exchange on the wire. That goes on top on the regular libp2p secure channel which uses standard tls security by default. You can tunnel what you want through a libp2p stream (ipfs p2p offers experimental funcionality for this).
@ipfsme I’m curious of the packets contain enough information for ISPs (or other infrastructure backbone) to identify what is IPFS traffic, or even the CID being referenced? If so we can expect to be censored at the whim of those corporations, just like they’re doing to the social media platforms whose politics they disagree with.
Regardless, I run IPFS inside a docker container (the dockerized GO-IPFS instance) so nothing outside that docker container can see any of the files. Also, AFAIK the only way to ‘secure’ an IPFS gateway that’s directly exposed to the outside world (it’s API port) would be to use a ‘reverse proxy’, and I think that may be what you meant by “reverse tunnel for traffic”.
If I capture a TLS session via wireshark, the protocol is listed as TLSv1.3 or 1.2 or whatever… I can watch the key exchange. However, there doesn’t seem to be any packet level cryptographic cover on any part of any ipfs conversation. I’ve looked through an entire exchange including starting a remote private node. I just don’t see how the secure channel functions in libp2p and what that secure channel would look like from a packet standpoint if I’m sitting at a router capturing traffic.
I do see Node IDs in the network stream along with associated IP addresses. So, there’s at least a little bit of information leakage regarding the IPFS network and the fact that the traffic is IPFS regardless of whether the port is 4001 or 13001.
I’ve tried to figure out if I can read or decode expected plain ASCII text being transferred, but I can’t. So, I suppose the data encryption occurs before transmission over the network. If so, this is fine from a user data standpoint… but not necessarily a metadata or traffic analysis standpoint… An ISP will be able to perform enough traffic analysis to figure out that IPFS traffic is being passed, the node IDs associated, and approximately how much data is being transferred to all endpoints. I’m not sure I like that idea.
EDIT:
OK… I found a starting point document for looking at libp2p secure communications architecture… I’m sure it’s been posted before around here… but I’ll read it this time…
After reading the github post, I’m still not sure how I can affirmatively verify that the TCP traffic between IPFS nodes I control and specifically two nodes setup as a private network is encrypted via TLS.
According to the documentation, the protocol identifier should be /tls/1.0.0
But I don’t see that protocol listed in the ipfs id output of any running node either in a private network or not… wireshark does not show any packet level encryption – no designation of TLS anywhere in the packet capture… How can I affirmatively and independently verify that the IPFS traffic between my nodes is TLS encrypted?
I understand that libp2p can be used for the same purpose… that’s something I’m very interested in enabling. However, I know my way around ssh and have a decent grasp on its security and general operation. I’m not quite sure how libp2p secure communication works… and am not sure how to “see it in operation” at the packet level.
The first tcp packet is not encrypted, but afterwards connections are upgraded, using a security transport supported by both sides. I suspect wireshark does not detect the upgrades and keeps listing TCP traffic, but the payloads will be garbled when connections are upgraded.
Well yes, those are mDNS multicasts to your local network. That is how IPFS makes autodiscovery on LANs. You can disable mDNS in the config if that bothers you.