Search code examples
network-programmingp2pnatnetwork-securitydecentralized-applications

Decentralized Application over NAT


I am currently writing a P2P application using golang. I have chosen Noise for that, since it provides an easy to use network stack.

My application provides a REST API that can be accessed via localhost. Data that are sent to the locally provided endpoints will then be transferred to all connected peers, which then distribute the data to their connected peers to keep the network synchronized.

So far I have succeeded with my implementation, however this only works for publicly exposed nodes or nodes within the same Network.

I would like to keep the usability of my application as easy as possible, also for users in private networks. Therefore I want to avoid manual configuration overhead (i.e. port forwarding in their router settings). If at all possible, I also would like to avoid using a central server for the NAT-Traversal, since my goal is to have a truly decentralized application.

I understand that there are several NAT-Traversal techniques, such as STUN and TURN, alongside others, and I am aware that Noise offers already NAT-PMP and UPnP, but somehow I cannot wrap my head around how exactly they work.

I know, that some VoIP or File-Sharing services use NAT-PMP and they seem to work on pretty much every Network, without any user interaction. That just seems a little weird to me and I am stuck.

How is it possible, that my application just magically changes some Router configurations to accept incoming traffic? To me that seems to be a huge security risk, especially if the user of my application does not even know about it. Also, I figured that not every Router supports NAT-PMP and UPnP. What if my users have one of those?


Solution

  • How is it possible, that my application just magically changes some Router configurations to accept incoming traffic? To me that seems to be a huge security risk, especially if the user of my application does not even know about it.

    Opening an incoming port only makes you as insecure as the network stack of the particular application listening on it is and that insecurity potential is not all that different from a client-server model.

    Take your browser for example. Whenever you visit some random internet site that includes an ad network some malicious entity might have placed ads pointing to their servers. If your browser has a vulnerability then it could be exploited.

    If your P2P application does not have a port opened it would still establish outgoing connections to various nodes in the P2P network and if one of those is malicious and your application is vulnerable then it can be exploited.

    Opening a port for incoming connections only changes the equation so far that attackers can exploit certain kinds of vulnerabilities (generally those low in the network stack, early in the connection setup, e.g. in pre-auth message parsing) without waiting for you to come by, they can visit you. It is a difference, but in practice a rather small one.

    Someone has to open their ports anyway, otherwise nobody on the internet could talk to anyone else.

    In the end it is far more important to focus on hardening the network stack of applications that are supposed to be exposed to the internet.

    The benefit of firewalls lies mostly in avoiding accidental exposure of services that are not written with security in mind, either legacy services or simply on the assumption that only internal users are supposed to access them. They reduce unnecessary attack surface.

    NAT-PMP and similar on the other hand exist to allow you to create necessary attack surface, simply because applications could not function otherwise without the ability to use the network.

    Also, I figured that not every Router supports NAT-PMP and UPnP. What if my users have one of those?

    UDP hole punching is a NAT traversal strategy that does not require cooperation from the router.

    Additionally you can ask users to adjust their firewalls/port forwarding rules manually.

    But if all nat traversal strategies fail then the next question is whether direct peer-peer connections are necessary for your protocol to work. For example in bittorrent they are not, in its case it is sufficient to form a connected graph, not a fully connected graph. Similar things can work for group chats.

    For one-on-one communication you have the option of either informing the user that their network is blocking the connection or to utilize altruistic (or paid-for) nodes providing data relay services.