0

I have an idea to host a web app that without built-in authentication on my server. And protect it by nftables, WireGuard and Reverse Path Forwarding only. The web server will listen to the server's WireGuard interface address, 10.0.0.1 in this example.

Princple:

  • The WireGuard use public-key cryptography to authenticate users, similar to the behavior of SSH public key authentication
  • fib daddr . iif type != local, Reverse Path Forwarding and the wg0 interface address 10.0.0.1/24 can restrict only the wg0's peer can access 10.0.0.1
  • web server will only listen to 10.0.0.1

Is that secure? Is there any potential vulnerability? Any comments are appreciated.

sysctl

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

The server's WireGuard interface

#wg0
[Interface]
Address = 10.0.0.1/24

# My trusted device
[Peer]
PublicKey = $server_publickey
AllowedIPs = 10.0.0.2/32

nftables.conf

table ip filter {
    chain PREROUTING {
        type filter hook prerouting priority filter; policy accept;
        fib daddr . iif type != local drop
    }
    
}

Update, A real example

To secure a Syncthing GUI on server without using password

  • The Syncthing GUI is listening 127.0.0.1:8384
  • User device will access the GUI through Apache reverse proxy
  • The Apache reverse proxy is opened to Internet because the server is hosting other services.
  • The http request is coming a VPS router via WireGuard.
<VirtualHost *:443>
    ServerName syncthing.$DOMAIN
    SSLEngine on
    ProxyPass / http://localhost:8384/
    ProxyPassReverse / http://localhost:8384/

    <Location "/">
        Require ip 10.1.0
    </Location>
</VirtualHost>
chain STRONG {
    type filter hook input priority raw; policy accept;
    ip saddr 10.1.0.0/24 iifname != { "lo", "wg0" } drop
}
[Interface]
Address = $home_server_wg_ip_address/30
PrivateKey = $home_server_privatekey
Table = $VPS_INTERFACE_TABLE
PreUp = ip rule add from $home_server_wg_ip_address/32 lookup $VPS_INTERFACE_TABLE priority $VPS_INTERFACE_TABLE_PRIORITY
PostDown = ip rule del from $home_server_wg_ip_address/32 lookup $VPS_INTERFACE_TABLE priority $VPS_INTERFACE_TABLE_PRIORITY

[Peer]
PublicKey = $vps_publickey
Endpoint = $vps_ip_address:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Waiho
  • 13
  • 3

1 Answers1

0

Yes, that would secure the web app so it could be accessed remotely only through the WireGuard tunnel (ie only from your "trusted device", 10.0.0.2, in your example).

But it's usually best to set up your nftables rules to block access to all the network services running on your server by default, and explicitly allow only authorized exceptions: eg:

table inet filter {
    chain input {
        # drop packets by default
        type filter hook input priority 0; policy drop;

        # accept loopback packets
        iif "lo" accept
        # accept icmp/icmpv6 packets
        ip protocol icmp accept
        ip6 nexthdr ipv6-icmp accept
        # accept already-established connections
        ct state established,related accept

        # accept new WireGuard connections
        udp dport 51820 accept
        # accept new connections to web app from WireGuard network
        tcp dport 80 iifname "wg0" accept
        # accept new SSH connections from LAN
        tcp dport 22 ip saddr 192.168.1.0/24 accept
        # ...
    }
}

If you did that, you wouldn't need to restrict your web app to listening on 10.0.0.1, or use that fib nftables rule, or turn on reverse-path filtering -- instead, all your access-control measures would be in one place, where they'd be easy to review or update in the future.


And yes, your updated example would secure the Syncthing GUI so it could be accessed only from devices on your WireGuard network. You're largely relying on Apache for security in this case, though, not nftables -- so you'd want to be careful about anything that could override Apache's client-IP tracking (principally mod_remoteip).

Justin Ludwig
  • 1,006
  • 7
  • 8
  • Finally, I have to implement this idea on a practical requirement. It is to secure the Syncthing GUI on the server, without using password. The GUI is listening to 127.0.0.1:8384. The user device will access the GUI through Apache reverse proxy. But the Apache is opened to the Internet also because I have hosted other services on this server, so filtering tcp port by iifname is not possible in my case. I utilized strong host model concept and Apache access control to accomplish this requirement. Could you take a look on the updated code. Anyway, appreciate your reply. – Waiho Jul 29 '22 at 10:26
  • oh, I'm so sorry. The update do not have inbox notification. I just read your comment today. Yes, my original setup is using a HAProxy TCP load balancer on the VPS, to accept Internet traffic and forward to my server via WireGuard tunnel. Now I changed it back to traditional port forwarding, because I did a experiment that the VPS can spoof IP address 10.1.0.x when using proxy protocol. But, at the end, I discover that this no-password idea is awkward. Finally I am not only using password on the server's Syncthing GUI, I use password on the desktop's Synchting GUI also, lol. – Waiho Aug 14 '22 at 03:27
  • Because I find that I can access these GUI on my other Windows account, those are standard account used for non open source, not fully trusted software. Moreover, I find that the Syncthing Android client by default use a random password. The security of application layer should really done on application layer. – Waiho Aug 14 '22 at 03:31
  • Also, I think the nft rule in my updated example is important also because my special routing rule, see the last code snippet in my update. I remember that spoofing is success without that nft rule. – Waiho Aug 14 '22 at 03:54