[英]How can I have a PHP script run a shell script as root?
運行Fedora 9/10,Apache 2,PHP 5 ......
我可以使用exec()從PHP腳本以root身份運行shell腳本嗎?
我只是給Apache root priveleges,然后在他們面前添加“sudo”命令?
具體來說,我正在嘗試啟動和停止后台腳本。
目前我有一個只運行應用程序的shell腳本start.sh:
#!/bin/bash
/path/to/my/app/appname
以及殺死應用程序的腳本stop.sh:
#!/bin/bash
killall appname
我會這樣做:
<?php
exec("sudo start.sh");
?>
提前致謝。
你不能只是sudo那樣,你需要先在/ etc / sudoers文件中設置無密碼sudo。 例如,可以使用visudo命令完成此操作。 確保在sudoers文件中設置權限,以便將apache用戶限制為您希望運行的單個命令(即shell腳本)。
即使這樣,它也會帶來安全風險,因為任何人都可以創建PHP腳本並依次運行shell腳本。 因此,請確保shell腳本本身不會受到Apache用戶的更改。
第二部分, 基拉爾 ,甚至更成問題。 您不應該只允許Apache以root權限運行killall。 您應該將killall包裝在另一個shell腳本中,並授予對sudoers中的訪問權限。
最后:不要使用root帳戶運行Apache,也不要使用setuid。 兩者都打開了一堆蠕蟲,因為你是一個新手(考慮到你提出的問題),你很可能會錯過一些會產生潛在問題的小細節。
不要以root
身份運行Apache。 Apache的設計非常適合以root
身份啟動,然后盡快放棄其權限
不要在你的腳本中使用sudo
- 太容易讓sudo
配置錯誤,以至於你服務器上運行的任何腳本都可以運行它喜歡的任何程序使用root
權限
看看讓你自己的程序運行“setuid”,這樣它就會獲得root權限,但是當它不再需要它們時就會丟棄它們(就像Apache一樣)
確保任何不能運行它的人都無法運行“setuid”可執行文件。
我在這個領域不專業,但看起來你需要SUID標志。
在這里閱讀示例或谷歌
你不想給Apache root。
您的問題還有另一種解決方案。 問題是Apache無法終止進程,因為它由root擁有。 您可以做的是將所有者更改為'www-data',這是Apache所識別的。
如果進程是服務並在啟動時啟動,則可以添加
sudo -u www-data <start-up script>
這樣www-data將成為該進程的所有者,因此運行關閉腳本將起作用。
你需要一層抽象來至少提供一點安全性!......
我這樣做的方法是在Python中編寫一個帶有root privs的簡單UDP服務器*:在給定端口上監視傳入的UDP數據包,如果它們匹配則將它們與白名單進行比較執行操作
然后你有一點PHP用預定義的消息向Python服務器發送消息......
<?php
$handle = fsockopen("udp://localhost",12345);
fwrite($handle,"Start Script");
fclose($handle);
?>
python服務器在端口12345上監視數據包,但只是忽略任何不是“啟動腳本”或“停止腳本”的數據包,因為它以root身份運行它可以愉快地啟動你的bash腳本。 你絕對必須使用白名單,直接從UDP套接字向命令行發送任何輸入真是不安全!
請注意,UDP可以被欺騙,因此如果您的防火牆允許欺騙入站流量(它真的不應該!),有人可以將偽造的數據包發送到您的Python服務器並停止/啟動您的服務。 這不太可能是一個問題,但如果您無法修復防火牆並且想要防范它,您可以使用無法欺騙的TCP / IP重做上述內容。
羅傑希思科特。
*這是一個非常簡單的服務器(約20行),但如果你不知道如何只是給我發消息,我會發送給你或在這里發布。
您可以考慮使用具有keepair身份驗證的localhost的ssh連接到具有root權限的帳戶。 在這樣的設置中,您不需要為您的網絡服務器進行root訪問。
根據要求,這是python服務器......
#!/usr/bin/python
import os
import socket
print " Loading Bindings..."
settings = {}
line = 0
for each in open('/path/to/actions.txt', 'r'):
line = line + 1
each = each.rstrip()
if each <> "":
if each[0] <> '#':
a = each.partition(':')
if a[2]:
settings[a[0]] = a[2]
else:
print " Err @ line",line,":",each
print " Starting Server...",
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print "OK."
print " Listening on port:", port
while True:
datagram = s.recv(1024)
if not datagram:
break
print "Rx Cmd:", datagram
if settings.has_key(datagram):
print "Launch:", settings[datagram]
os.system(settings[datagram]+" &")
s.close()
配置文件“actions.txt”使用格式“action-name:associated-shell-command”即
# Hash denotes a comment
webroot:nautilus /var/www
ftp:filezilla
edit_homepage:gedit /var/www/homepage/htdocs/index.php
這段代碼不檢查傳入的UDP數據包的原始IP,因為我在localhost上運行它,我被其他任何人防火牆檢查,無論如何檢查都不會提供欺騙保護。
我沒有時間重寫它以使用TCP / IP,但Python是一種值得了解的語言,所以如果你真的想要這個功能,我會留給你一個google的'Python'和'SOCK_STREAM' 。 這可能不值得你的麻煩,它更容易配置你的防火牆,以便沒有欺騙的localhost數據包可以通過並修改代碼,以確保它只偵聽來自環回的數據包。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.