Is there a way for non-root processes to bind to “privileged” ports on Linux?

后端 未结 24 1290
予麋鹿
予麋鹿 2020-11-22 02:04

It\'s very annoying to have this limitation on my development box, when there won\'t ever be any users other than me.

I\'m aware of the standard workarounds, but non

相关标签:
24条回答
  • 2020-11-22 02:46

    At startup:

    iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
    

    Then you can bind to the port you forward to.

    0 讨论(0)
  • 2020-11-22 02:46

    Bind port 8080 to 80 and open port 80:

    sudo iptables -t nat -A OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080
    sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
    

    and then run program on port 8080 as a normal user.

    you will then be able to access http://127.0.0.1 on port 80

    0 讨论(0)
  • 2020-11-22 02:48

    Since the OP is just development/testing, less than sleek solutions may be helpful:

    setcap can be used on a script's interpreter to grant capabilities to scripts. If setcaps on the global interpreter binary is not acceptable, make a local copy of the binary (any user can) and get root to setcap on this copy. Python2 (at least) works properly with a local copy of the interpreter in your script development tree. No suid is needed so the root user can control to what capabilities users have access.

    If you need to track system-wide updates to the interpreter, use a shell script like the following to run your script:

    #!/bin/sh
    #
    #  Watch for updates to the Python2 interpreter
    
    PRG=python_net_raw
    PRG_ORIG=/usr/bin/python2.7
    
    cmp $PRG_ORIG $PRG || {
        echo ""
        echo "***** $PRG_ORIG has been updated *****"
        echo "Run the following commands to refresh $PRG:"
        echo ""
        echo "    $ cp $PRG_ORIG $PRG"
        echo "    # setcap cap_net_raw+ep $PRG"
        echo ""
        exit
    }
    
    ./$PRG $*
    
    0 讨论(0)
  • 2020-11-22 02:49

    TLDR: For "the answer" (as I see it), jump down to the >>TLDR<< part in this answer.

    OK, I've figured it out (for real this time), the answer to this question, and this answer of mine is also a way of apologizing for promoting another answer (both here and on twitter) that I thought was "the best", but after trying it, discovered that I was mistaken about that. Learn from my mistake kids: don't promote something until you've actually tried it yourself!

    Again, I reviewed all the answers here. I've tried some of them (and chose not to try others because I simply didn't like the solutions). I thought that the solution was to use systemd with its Capabilities= and CapabilitiesBindingSet= settings. After wrestling with this for some time, I discovered that this is not the solution because:

    Capabilities are intended to restrict root processes!

    As the OP wisely stated, it is always best to avoid that (for all your daemons if possible!).

    You cannot use the Capabilities related options with User= and Group= in systemd unit files, because capabilities are ALWAYS reset when execev (or whatever the function is) is called. In other words, when systemd forks and drops its perms, the capabilities are reset. There is no way around this, and all that binding logic in the kernel is basic around uid=0, not capabilities. This means that it is unlikely that Capabilities will ever be the right answer to this question (at least any time soon). Incidentally, setcap, as others have mentioned, is not a solution. It didn't work for me, it doesn't work nicely with scripts, and those are reset anyways whenever the file changes.

    In my meager defense, I did state (in the comment I've now deleted), that James' iptables suggestion (which the OP also mentions), was the "2nd best solution". :-P

    >>TLDR<<

    The solution is to combine systemd with on-the-fly iptables commands, like this (taken from DNSChain):

    [Unit]
    Description=dnschain
    After=network.target
    Wants=namecoin.service
    
    [Service]
    ExecStart=/usr/local/bin/dnschain
    Environment=DNSCHAIN_SYSD_VER=0.0.1
    PermissionsStartOnly=true
    ExecStartPre=/sbin/sysctl -w net.ipv4.ip_forward=1
    ExecStartPre=-/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
    ExecStartPre=-/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
    ExecStartPre=/sbin/iptables -A INPUT -p udp --dport 5333 -j ACCEPT
    ExecStartPre=/sbin/iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
    ExecStopPost=/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
    ExecStopPost=/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
    User=dns
    Group=dns
    Restart=always
    RestartSec=5
    WorkingDirectory=/home/dns
    PrivateTmp=true
    NoNewPrivileges=true
    ReadOnlyDirectories=/etc
    
    # Unfortunately, capabilities are basically worthless because they're designed to restrict root daemons. Instead, we use iptables to listen on privileged ports.
    # Capabilities=cap_net_bind_service+pei
    # SecureBits=keep-caps
    
    [Install]
    WantedBy=multi-user.target
    

    Here we accomplish the following:

    • The daemon listens on 5333, but connections are successfully accepted on 53 thanks to iptables
    • We can include the commands in the unit file itself, and thus we save people headaches. systemd cleans up the firewall rules for us, making sure to remove them when the daemon isn't running.
    • We never run as root, and we make privilege escalation impossible (at least systemd claims to), supposedly even if the daemon is compromised and sets uid=0.

    iptables is still, unfortunately, quite an ugly and difficult-to-use utility. If the daemon is listening on eth0:0 instead of eth0, for example, the commands are slightly different.

    0 讨论(0)
  • 2020-11-22 02:49

    Use the privbind utility: it allows an unprivileged application to bind to reserved ports.

    0 讨论(0)
  • 2020-11-22 02:50

    For some reason no one mention about lowering sysctl net.ipv4.ip_unprivileged_port_start to the value you need. Example: We need to bind our app to 443 port.

    sysctl net.ipv4.ip_unprivileged_port_start=443
    

    Some may say, there is a potential security problem: unprivileged users now may bind to the other privileged ports (444-1024). But you can solve this problem easily with iptables, by blocking other ports:

    iptables -I INPUT -p tcp --dport 444:1024 -j DROP
    iptables -I INPUT -p udp --dport 444:1024 -j DROP
    

    Comparison with other methods. This method:

    • from some point is (IMO) even more secure than setting CAP_NET_BIND_SERVICE/setuid, since an application doesn't setuid at all, even partly (capabilities actually are). For example, to catch a coredump of capability-enabled application you will need to change sysctl fs.suid_dumpable (which leads to another potential security problems) Also, when CAP/suid is set, /proc/PID directory is owned by root, so your non-root user will not have full information/control of running process, for example, user will not be able (in common case) to determine which connections belong to application via /proc/PID/fd/ (netstat -aptn | grep PID).
    • has security disadvantage: while your app (or any app that uses ports 443-1024) is down for some reason, another app could take the port. But this problem could also be applied to CAP/suid (in case you set it on interpreter, e.g. java/nodejs) and iptables-redirect. Use systemd-socket method to exclude this problem. Use authbind method to only allow special user binding.
    • doesn't require setting CAP/suid every time you deploy new version of application.
    • doesn't require application support/modification, like systemd-socket method.
    • doesn't require kernel rebuild (if running version supports this sysctl setting)
    • doesn't do LD_PRELOAD like authbind/privbind method, this could potentially affect performance, security, behavior (does it? haven't tested). In the rest authbind is really flexible and secure method.
    • over-performs iptables REDIRECT/DNAT method, since it doesn't require address translation, connection state tracking, etc. This only noticeable on high-load systems.

    Depending on the situation, I would choose between sysctl, CAP, authbind and iptables-redirect. And this is great that we have so many options.

    0 讨论(0)
提交回复
热议问题