2012-05-11 2 views
5

Я написал свой собственный веб-сервер в C. Как связать его с портом 80 без root, чтобы безопасность не подвергалась риску (переполнение буфера и т. Д.)?Привязать веб-сервер к порту 80 без корня

Должен ли я просто перенаправлять любой трафик с другого «стабильного» сервера, который работает на порту 80?

ответ

5

Использование передового прокси-сервера действительно является самым простым и наиболее рекомендуемым решением. Это также имеет преимущество фильтрации ужасно недействительных запросов, прежде чем они даже дойдут до вашего собственного письменного сервера.
В случае, если ваше приложение использует IP-адрес пользователя для чего-либо, не забудьте извлечь его из любого заголовка, который использует ваш веб-сервер (X-Client-IP и т. Д.). Тем не менее, делайте это только для запросов, которые действительно поступают с вашего веб-сервера, иначе пользователи могут обманывать свой IP-адрес. Вы можете сделать это, проверив, пришел ли запрос с вашего IP-адреса и только проверьте заголовок в этом случае или просто привяжите приложение к localhost.

Другим решением будет предоставление программы CAP_NET_BIND_SERVICE. Это требует, чтобы root использовал setcap cap_net_bind_service=ep /path/to/the/executable - поскольку флаг хранится в атрибуте файловой системы, он будет потерян при копировании файла в другую систему или перекомпиляции приложения.

Конечно, вы также можете внести свой root setuid в программу и затем переключиться на непривилегированного пользователя сразу после вызова bind(). Однако, в зависимости от того, как работает ваша программа и что она делает, это может быть не очень хорошая идея - например, если ей по какой-то причине нужно закрыть и снова открыть гнездо для прослушивания, для этого потребуется полный перезапуск процесса.

+0

+1 для возможностей, хотя они не переносятся ни на один другой unix. – dwalter

+0

Большинство людей используют Linux в любом случае. И я думаю * BSD имеет нечто похожее. – ThiefMaster

2

Если вы хотите связать свой сервер с портом 80, вы должны сделать это с правами root и впоследствии отказаться от привилегий.

bind(sockfd, addr, addrlen); 
/* process is running as root, drop privileges after bind*/ 
if (setgid(groupid) != 0) 
    errx(1, "setgid: Unable to drop group privileges: %s", strerror(errno)); 
if (setuid(userid) != 0) 
    errx(1, "setuid: Unable to drop user privileges: %S", strerror(errno)); 

Как я могу привязать его к порту 80, не будучи корнем, так что безопасность не нарушена (переполнение буфера и т.д.)

не запущена, как корень делает не сделать свой система более безопасна, это просто добавляет еще один слой для использования. Таким образом, вместо того, чтобы думать о том, как не бежать как корень, пожалуйста, убедитесь, что вы не использовать любую известную нестабильную функцию, такие как strcpy(), sprintf() и т.д., но вместо того, чтобы использовать strncpy(), snprintf() и т.д.

+0

Следует отметить, что 'errx' является нестандартной функцией, доступной на многих BSD-совместимых системах. Если вам нужна его функциональность (тривиальная функция из 2-3 строк), вы должны написать свой собственный, чтобы не повредить переносимость вашей программы. –

3

Альтернативу вызова bind() как root, а затем отказаться от привилегий, - это иметь корневой процесс, который создает сокет и связывает его, а затем передает прослушивающий сокет в непривилегированный процесс через соединение сокета UNIX-домена с помощью сообщения SCM_RIGHTS.

2

Ну, как вы знаете, все порты под 1024 в Unix требуют прав root для открытия. В системе Unix вам не нужны как можно меньше приложений с привилегиями root. Это всегда будет большой риск для безопасности.

Альтернативой является использование iptables для перенаправления трафика порта 80 на более безопасный порт, такой как 8080. Вот description о том, как его настроить.

Iptables - это не самый простой инструмент для настройки, но как только вы его освоили, он очень полезен и эффективен (и защищен).

+0

Для меня это работало только в таблице NAT в цепочке OUTPUT. Но это самый прямой ответ на вопрос. – nus

0

Я работал над этой проблемой в течение достаточно долгого времени, и пришли к выводу, что systemd + iptables является решением, и не возможности, так как elaborated in great detail here.