Разрешение пользователю разрешить прослушивать порт ниже 1024

63

Мне нужно разрешить пользователю (отличному от root) запускать сервер, прослушивающий порт 80.

Есть какой-либо способ сделать это?

peoro
источник
1
Этот вопрос открыт для интерпретации. Я надеюсь, что вы имеете в виду «вы создали новую системную службу, которую вы (как root) хотели бы запустить в непривилегированной учетной записи по соображениям безопасности» (считается хорошей практикой), а не «у меня есть пользователь, который спрашивает, могут ли они запустить собственный веб-сервер в моей системе, как мне разрешить им доступ? " (считается довольно плохой практикой)
Майкл Шоу
3
@Ptolemy, настоящая причина такова: моя машина находится за брандмауэром, который блокирует любой порт, кроме 80. Я хочу разместить сервер (который не сбрасывает привилегии!), Поэтому мне нужно, чтобы он прослушивал порт 80, но не не доверяйте запуску с правами root (по очевидным причинам безопасности). Мне разрешено делать это, если тебе интересно.
peoro
serverfault.com/questions/112795/…
Сиро Сантилли 新疆 新疆 中心 法轮功 六四 事件

Ответы:

50

setcap 'cap_net_bind_service=+ep' /path/to/program

это будет работать для конкретных процессов. Но чтобы позволить конкретному пользователю привязываться к портам ниже 1024, вам придется добавить его в sudoers.

Посмотрите на это обсуждение для более.

Рохан Монга
источник
31

(Некоторые из этих методов были упомянуты в других ответах; я даю несколько возможных вариантов в грубом порядке предпочтений.)

Вы можете перенаправить низкий порт на высокий порт и прослушивать высокий порт.

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 1080

Вы можете запустить свой сервер как root и удалить привилегии после того, как он начал прослушивать привилегированный порт. Желательно, вместо того, чтобы кодировать это самостоятельно, запустить свой сервер из оболочки, которая сделает эту работу за вас. Если ваш сервер запускает один экземпляр для каждого соединения, запустите его из inetd(или аналогичной программы, такой как xinetd). Для inetd, используйте строку, как это в /etc/inetd.conf:

http  stream  tcp  nowait  username:groupname  /path/to/server/executable  argv[0] argv[1]…

Если ваш сервер прослушивает один экземпляр, запустите его из такой программы, как authbind. Либо создайте пустой файл /etc/authbind/byport/80и сделайте его исполняемым для пользователя, работающего на сервере; или создайте /etc/authbind/byuid/1234, где 1234 - это UID, на котором работает сервер, содержащий строку 0.0.0.0/0:80,80.

Если исполняемый файл вашего сервера хранится в файловой системе, которая поддерживает возможности, вы можете предоставить ему такую возможность . Остерегайтесь, что возможности все еще относительно новы и все еще имеют несколько изломов .cap_net_bind_service

setcap cap_net_bind_service=ep /path/to/server/executable
Жиль "ТАК - перестань быть злым"
источник
4
В каждом случае, с которым мне приходилось иметь дело, исполняемый файл представлял собой скрипт, запускающий Java или Python. Будучи парнем без 10 часов, чтобы тратить на тонкости, ваше решение iptables покрывает это безболезненно.
пахнет
Для решения iptables мне также пришлось добавить правило фильтра, так как в -A INPUT -p tcp --dport 1080 -j ACCEPTпротивном случае оно не сработало бы (у меня также есть универсальное решение -j DROP). Поэтому у меня осталось два сокета прослушивания.
thom_nic
4

Короткий ответ: это невозможно по замыслу.

Длинный ответ заключается в том, что в мире с открытым исходным кодом много людей играют с дизайном и придумывают альтернативные методы. В целом это общепринятая практика, что это не должно быть возможным. Тот факт, что вы пытаетесь, вероятно, означает, что у вас есть другая ошибка проектирования в вашей системе, и вам следует пересмотреть всю архитектуру вашей системы в свете лучших рекомендаций * nix и последствий для безопасности.

Тем не менее, одна программа для авторизации некорневого доступа к низким портам - это authbind . И selinux, и grsecurity также предоставляют фреймворки для таких тонко настроенных аутентификаций.

Наконец, если вы хотите, чтобы определенные пользователи запускали определенные программы от имени пользователя root, и вам действительно нужно просто позволить пользователю перезапустить apache или что-то в этом роде, sudoваш друг!

Калеб
источник
8
Портовая «охрана» на самом деле мало что дает в современном мире.
pjc50
3
@ pjc50: Да, это так. Это подразумеваемое доверие. Низкие номера портов подразумевают высокое доверие. Ожидается, что SSH, POP, FTP и другие демоны будут запрашивать пароли системного уровня и другие учетные данные, когда их порты открыты. Если пользователям было разрешено прослушивать порты с низким уровнем на коробке, они могли запускать фальшивые демоны на неиспользуемых (или сбойных) портах и ​​собирать пароли от ничего не подозревающих пользователей. Эти пароли могут затем использоваться в этом поле для взлома других учетных записей, включая root.
Калеб
8
Это довольно слабая форма безопасности. Если вы подключились к чему-то и не сделали транзакцию сертификата, то вы не представляете, с кем говорите - например, атаки MITM.
pjc50
5
Я полагаю, что нужно настроить chown для портов: тогда вы можете «chown mail port25», тогда (a) ваш почтовый демон не должен запускаться с привилегированными правами root и (b) никто другой не сможет его взломать.
pjc50
7
Хотя это могло быть правдой «по замыслу», когда Linux был в зачаточном состоянии, это имеет очень мало смысла тогда и сейчас. Безопасность - это все о том, что пользователь может и не может сделать. Например, разрешение только пользователю root использовать порт 80 является огромной угрозой безопасности, поскольку это означает, что вы должны предоставить root-доступ людям, которым нужно использовать порт 80, но не должны иметь root-доступ. Если вы доверяете некорневому пользователю X использовать порт 80, вы сможете закодировать это доверие в вашей ОС. К счастью, как вы упомянули, есть дурацкие обходные пути, которые позволяют это, например, authbind.
BT
3

Вы можете использовать переадресацию портов netcat, xinetd или iptables или использовать apache в качестве внешнего прокси-сервера и запускать процесс на непривилегированном порту.

jamespo
источник
3

Authbind , @Gilles уже упоминал об этом, но я бы хотел немного рассказать об этом.

Он имеет удобное управление доступом (подробности на странице руководства): вы можете фильтровать доступ по порту, адресу интерфейса, uid, диапазонам адресов или портов и их комбинации.

У него очень полезный параметр --depth:

- глубокие уровни

Заставляет authbind влиять на программы, находящиеся глубоко в графе вызовов. По умолчанию это 1.

«Уровень глубоко» означает, что когда скрипт (или программа) запускает другой скрипт, он опускается на уровень. Таким образом, если у вас есть --depth 5это, значит, на уровнях 1 (или 0?) Через 5 у вас есть разрешение на привязку, а на уровне 6 и выше - нет. Полезно, когда вы хотите, чтобы у скрипта был доступ, но не у программ, с которыми он работает или без вашего ведома.


Для иллюстрации, у вас может быть что-то вроде этого: в целях безопасности у вас есть пользователь, javaкоторый предназначен только для запуска Java, и вы хотите дать ему доступ к порту 80:

echo > /etc/authbind/byport/80
chown root:java /etc/authbind/byport/80
chmod 710 /etc/authbind/byport/80

Я создал ../byport/80 file, дал его javaгруппе пользователей (у каждого пользователя есть своя группа) и сделал его исполняемым по группе, что означает, что он исполняется javaпользователем. Если вы предоставляете доступ по порту, файл должен быть исполняемым пользователем, который должен иметь доступ, поэтому мы сделали это.

Этого может быть достаточно для обычного Джо, но, поскольку вы знаете, как использовать --depthпараметр, вы запускаете (как javaпользователь), authbind --depth [depth] my_web_app's_start_scriptначиная --depth 1и продолжая свой путь, пока не найдете наименьшую глубину, которая работает, и используйте ее.

Прочитайте справочную страницу для деталей .

Доминикас Мостаускис
источник
1

Я пробовал метод iptables PREROUTING REDIRECT, но обнаружил, что он также влияет на перенаправленные пакеты. То есть, если машина также пересылает пакеты между интерфейсами (например, если она действует как точка доступа Wi-Fi, подключенная к сети Ethernet), то правило iptables также будет перехватывать подключения подключенных клиентов к адресатам Интернета и перенаправлять их на машина. Это не то, что я хотел - я только хотел перенаправить соединения, которые были направлены на саму машину.

Одна возможность - использовать переадресацию TCP-порта. Например, используя socat:

socat TCP4-LISTEN:www,reuseaddr,fork TCP4:localhost:8080

Однако одним из недостатков этого метода является то, что приложение, которое прослушивает порт 8080, не знает адрес источника входящих соединений (например, для регистрации или других целей идентификации).

Крейг МакКуин
источник