47

ポート 80 でリッスンを開始する Python プログラムを作成したいのですが、その後は root 権限なしで実行します。ルートを削除する方法、またはそれなしでポート 80 を取得する方法はありますか?

4

6 に答える 6

58

root権限がないと、ポート80でサーバーを開くことはできません。これはOSレベルの制限です。したがって、唯一の解決策は、ポートを開いた後にroot権限を削除することです。

Pythonでroot権限を削除するための可能な解決策は次のとおりです。Pythonで権限を削除します。これは一般的には良い解決策ですがos.setgroups([])、rootユーザーのグループメンバーシップが保持されないように関数に追加する必要もあります。

コードを少しコピーしてクリーンアップし、ロギングと例外ハンドラーを削除して、OSError適切に処理できるようにしました(プロセスが有効なUIDまたはGIDを切り替えることが許可されていない場合にスローされます)。

import os, pwd, grp

def drop_privileges(uid_name='nobody', gid_name='nogroup'):
    if os.getuid() != 0:
        # We're not root so, like, whatever dude
        return

    # Get the uid/gid from the name
    running_uid = pwd.getpwnam(uid_name).pw_uid
    running_gid = grp.getgrnam(gid_name).gr_gid

    # Remove group privileges
    os.setgroups([])

    # Try setting the new uid/gid
    os.setgid(running_gid)
    os.setuid(running_uid)

    # Ensure a very conservative umask
    old_umask = os.umask(077)
于 2010-04-23T15:53:50.663 に答える
12

を使用して Python プログラムを開始することをお勧めしauthbindます。そのため、root として実行する必要はありません。

https://en.wikipedia.org/wiki/Authbind

于 2011-11-18T18:05:35.293 に答える
7

特権を削除する必要があるときはいつでも、ユーザーにユーザー名とグループを入力するように求めるのは得策ではありません。これは、Tamás のコードをわずかに変更したバージョンで、権限を削除し、sudo コマンドを開始したユーザーに切り替えます。sudo を使用していると仮定しています (そうでない場合は、Tamás のコードを使用してください)。

#!/usr/bin/env python3

import os, pwd, grp

#Throws OSError exception (it will be thrown when the process is not allowed
#to switch its effective UID or GID):
def drop_privileges():
    if os.getuid() != 0:
        # We're not root so, like, whatever dude
        return

    # Get the uid/gid from the name
    user_name = os.getenv("SUDO_USER")
    pwnam = pwd.getpwnam(user_name)

    # Remove group privileges
    os.setgroups([])

    # Try setting the new uid/gid
    os.setgid(pwnam.pw_gid)
    os.setuid(pwnam.pw_uid)

    #Ensure a reasonable umask
    old_umask = os.umask(0o22)


#Test by running...
#./drop_privileges
#sudo ./drop_privileges
if __name__ == '__main__':
    print(os.getresuid())
    drop_privileges()
    print(os.getresuid())
于 2014-04-08T10:06:17.433 に答える
5
  1. systemd を介してプログラムを起動すると、systemd は既に開いているリッスン ソケットをそれに引き渡すことができ、最初の接続でプログラムをアクティブ化することもできます。デーモン化する必要さえありません。

  2. スタンドアロンのアプローチを使用する場合は、機能 CAP_NET_BIND_SERVICE が必要です (機能のマニュアル ページを確認してください)。これは、正しいコマンド ライン ツールを使用してプログラムごとに実行するか、アプリケーションを (1) suid root にする (2) 起動する (3) ポートをリッスンする (4) 特権/機能をすぐに削除することによって実行できます。 .

suid root プログラムには、多くのセキュリティ上の考慮事項が伴うことに注意してください (クリーンで安全な環境、umask、特権、rlimits、これらすべては、プログラムが正しく設定する必要があるものです)。systemd のようなものを使用できれば、なおさらです。

于 2011-11-18T21:09:06.800 に答える
2

スーパーユーザーになりたくない他のことをした後にソケットを要求する必要がない限り、これのほとんどは機能します。

少し前に、 tradesocketというプロジェクトを作成しました。これにより、posix システムでプロセス間でソケットをやり取りできます。私がしているのは、最初にスーパーユーザーのままのプロセスをスピンオフし、残りのプロセスはアクセス許可を落としてから、他のプロセスからソケットを要求することです。

于 2011-11-19T04:20:56.493 に答える