रूट विशेषाधिकार के साथ फ़ाइल में प्रोग्रामेटिक रूप से लिखने के लिए सबसे सुरक्षित तरीका क्या है?


35

एक विशाल आवेदन की जरूरत है, एक विशिष्ट समय में, एक फ़ाइल को कम संख्या में लिखने के लिए जिसे रूट अनुमतियों की आवश्यकता होती है। यह वास्तव में एक फ़ाइल नहीं है, लेकिन एक हार्डवेयर इंटरफ़ेस है जो लिनक्स में एक फ़ाइल के रूप में उजागर होता है।

पूरे एप्लिकेशन को रूट विशेषाधिकार देने से बचने के लिए, मैंने एक बैश स्क्रिप्ट लिखी जो महत्वपूर्ण कार्य करती है। उदाहरण के लिए, निम्न स्क्रिप्ट आउटपुट के रूप में हार्डवेयर इंटरफ़ेस के पोर्ट 17 को सक्षम करेगा:

echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction

हालांकि, जैसा suidकि मेरे सिस्टम पर बैश स्क्रिप्ट के लिए अक्षम है, मुझे आश्चर्य है कि इसे प्राप्त करने का सबसे अच्छा तरीका क्या है।

  1. यहां प्रस्तुत कुछ वर्कअराउंड का उपयोग करें

  2. स्क्रिप्ट sudoको मुख्य एप्लिकेशन से कॉल करें, और स्क्रिप्ट को कॉल करते समय पासवर्ड की आवश्यकता से बचने के लिए, तदनुसार sudoers सूची को संपादित करें। मैं sudo विशेषाधिकार देने के लिए थोड़ा असहज हूँ echo

  3. बस, एक C प्रोग्राम लिखें fprintf, और इसे रुट पर सेट करें। स्ट्रिंग्स और फाइलनाम को हार्डकोड करें और सुनिश्चित करें कि केवल रूट ही इसे संपादित कर सकता है। या एक पाठ फ़ाइल से तार पढ़ें, इसी तरह सुनिश्चित करें कि कोई भी फ़ाइल को संपादित नहीं कर सकता है।

  4. कुछ अन्य समाधान जो मेरे पास नहीं थे और सुरक्षित या सरल हैं, फिर जो ऊपर प्रस्तुत किए गए हैं?


10
आप अपना कार्यक्रम केवल रूट विशेषाधिकारों से शुरू क्यों नहीं करते, फ़ाइल को खोलें, और विशेषाधिकार छोड़ें? कि हर वेबसर्वर या ऐसा ही सॉकेट्स के लिए करता है। प्रभावी रूप से, आप जड़ के रूप में नहीं चल रहे हैं, न ही एक सहायक आवश्यक है जो करता है।
डेमन

जवाबों:


33

आपको sudoएक्सेस देने की आवश्यकता नहीं है echo। वास्तव में, यह व्यर्थ है क्योंकि, जैसे sudo echo foo > bar, पुनर्निर्देशन मूल उपयोगकर्ता के रूप में किया जाता है, जड़ के रूप में नहीं।

साथ छोटे स्क्रिप्ट कॉल sudoकी अनुमति NOPASSWD:के लिए उपयोग केवल उस स्क्रिप्ट (और किसी भी अन्य समान स्क्रिप्ट) उपयोगकर्ता द्वारा (रों) जो इसे करने के लिए उपयोग की जरूरत है।

यह हमेशा उपयोग करने का सबसे अच्छा / सबसे सुरक्षित तरीका है sudo। कम संख्या में उन समादेशों को अलग करें, जिन्हें अपने स्वयं के अलग स्क्रिप्ट (ओं) में रूट विशेषाधिकारों की आवश्यकता होती है और अन-ट्रस्टेड या आंशिक रूप से विश्वसनीय उपयोगकर्ता को केवल उस स्क्रिप्ट को रूट के रूप में चलाने की अनुमति देता है।

छोटे-से-योग्य sudoस्क्रिप्ट (ओं) को या तो उपयोगकर्ता से args (या इनपुट) नहीं लेना चाहिए (यानी किसी भी अन्य प्रोग्राम में इसे कॉल करने के लिए हार्ड-कोडेड विकल्प और args होना चाहिए) या इसे बहुत सावधानी से किसी भी तर्क / इनपुट को मान्य करना चाहिए जिसे इसे प्राप्त करना है उपयोगकर्ता से स्वीकार करते हैं।

सत्यापन में पागल होना - बाहर जाने के लिए 'ज्ञात खराब' चीजों की तलाश करने के बजाय, केवल 'ज्ञात अच्छी' चीजों को अनुमति दें और किसी भी बेमेल या त्रुटि या किसी भी चीज़ पर भी गर्भपात करें जो कि संदिग्ध हो।

सत्यापन यथासंभव स्क्रिप्ट में होना चाहिए (अधिमानतः इससे पहले कि यह रूट के रूप में कुछ भी करता है)।


जब मैंने पहली बार यह उत्तर लिखा था, तो मुझे वास्तव में इसका उल्लेख करना चाहिए था, लेकिन यदि आपकी स्क्रिप्ट एक शेल स्क्रिप्ट है, तो यह ठीक से सभी चर को उद्धृत करना चाहिएकिसी भी तरह से उपयोगकर्ता द्वारा आपूर्ति किए गए इनपुट वाले चर को उद्धृत करने के लिए विशेष रूप से सावधान रहें , लेकिन कुछ चर सुरक्षित नहीं हैं, सभी को समझें

यही कारण है कि वातावरण चर संभावित (जैसे उपयोगकर्ता द्वारा नियंत्रित शामिल "$PATH", "$HOME", "$USER"आदि और निश्चित रूप से शामिल है "$QUERY_STRING"और "HTTP_USER_AGENT"आदि एक CGI स्क्रिप्ट में)। वास्तव में, बस उन सभी को उद्धृत करें। यदि आपको कई तर्कों के साथ कमांड लाइन का निर्माण करना है, तो आर्ग्स सूची बनाने के लिए एक सरणी का उपयोग करें और कहा कि - "${myarray[@]}"

क्या मैंने कहा है "उन सभी को उद्धृत करें" अक्सर पर्याप्त होता है? इसे याद रखना। कर दो।


18
आपको लगता है कि स्क्रिप्ट ही किया जाना चाहिए उल्लेख करना भूल गया स्वामित्व , जड़ से अनुमतियों को 500 के साथ
वाइल्डकार्ड

13
कम से कम अच्छाई की खातिर, लेखन अनुमति को हटा दें। यह वास्तव में मेरी बात थी। बाकी बस सख्त है।
वाइल्डकार्ड

10
एक विचारशील लिखित सी कार्यक्रम में एक शेल स्क्रिप्ट की तुलना में एक छोटे हमले की सतह होगी।
user253751

7
@ इमिबिज़, संभवतः। लेकिन शेल स्क्रिप्ट की तुलना में इसे लिखने और डीबग करने में बहुत अधिक समय लगेगा। और एक सी संकलक की आवश्यकता होती है (जो कुछ उत्पादन सर्वरों पर निषिद्ध हैं ताकि हमलावरों को शोषण के लिए कठिन बनाकर सुरक्षा जोखिम को कम किया जा सके)। इसके अलावा, IMO एक नौसिखिया द्वारा मध्यवर्ती स्तर के sysadmin या प्रोग्रामर के लिए लिखी जाने वाली एक शेल स्क्रिप्ट है, जो समान कौशल वाले किसी व्यक्ति द्वारा लिखे गए C प्रोग्राम की तुलना में शोषक होने की संभावना कम है - खासकर अगर उसे उपयोगकर्ता-प्रदत्त डेटा को स्वीकार करना और मान्य करना है।
कास

3
@JonasWielicki - मुझे लगता है कि हम अब अच्छी तरह से और सही मायने में राय के स्थान पर हैं। आप या तो खोल या सी (या पर्ल या अजगर या awk आदि) के लिए वैध तर्क कर सकते हैं या तो कम या ज्यादा शोषण गलतियों का खतरा है। जब, वास्तव में, यह ज्यादातर प्रोग्रामर के कौशल और विस्तार (और थकान, जल्दबाजी, सावधानी, आदि) पर ध्यान देने पर निर्भर करता है। यह एक तथ्य है, हालांकि, निचले स्तर की भाषाओं को उच्च-स्तरीय भाषाओं में बहुत कम लाइनों-ऑफ-कोड में क्या किया जा सकता है, इसे प्राप्त करने के लिए अधिक कोड की आवश्यकता होती है .... और प्रत्येक एलओसी एक के लिए एक और अवसर है गलती होना।
कास

16

Gpio फ़ाइलों पर स्वामी की जाँच करें:

ls -l /sys/class/gpio/

सबसे अधिक संभावना है, आपको पता चलेगा कि वे समूह के स्वामित्व में हैं gpio:

-rwxrwx--- 1 root     gpio     4096 Mar  8 10:50 export
...

उस स्थिति में, आप gpioबिना sudo के एक्सेस देने के लिए अपने उपयोगकर्ता को समूह में जोड़ सकते हैं :

sudo usermod -aG gpio myusername

आपको प्रभावी होने के लिए लॉगआउट करना होगा और उसके बाद वापस लॉग इन करना होगा।


यह काम नहीं करता है। दरअसल, हर चीज का ग्रुप मालिक /sys/class/gpio/gpio है, लेकिन फिर भी खुद को उस ग्रुप में शामिल करने के बाद भी, जब भी मैं वहां कुछ भी लिखने की कोशिश करता हूं, तो मुझे "अनुमति से वंचित" कर दिया जाता है।
vsz

1
समस्या यह है, कि फाइलें /sys/class/gpio/वास्तव में केवल सहानुभूति होती हैं /sys/devices/platform/soc/<some temporary name>/gpioजहां मालिक और समूह दोनों जड़ होते हैं।
vsz

4
@vsz क्या आपने कोशिश की chgrp gpio /sys/devices/platform/soc/*/gpio? शायद ऐसा ही कुछ स्टार्टअप फाइल में डाला जा सकता है।
जपा

हाँ, लेकिन यह इतना आसान नहीं है। जैसा कि वे हमेशा एक अलग तरीके से उत्पन्न होते हैं, मुझे कुछ का उपयोग करना पड़ा जैसेchgrp gpio `readlink -f /sys/class/gpio/gpio18`/*
vsz

7

इसके लिए एक समाधान (विशेष रूप से लिनक्स डेस्कटॉप पर लेकिन अन्य मामलों में भी लागू होता है) प्राधिकरण करने के लिए रूट और पोलकिट के रूप में चलने वाली एक छोटी सेवा को सक्रिय करने के लिए डी-बस का उपयोग करना है। यह मूल रूप से क्या पोलकिट के लिए डिज़ाइन किया गया था ; इसके परिचयात्मक प्रलेखन से :

पोलकिट एक अधिकृत एपीआई प्रदान करता है जिसका उपयोग विशेषाधिकार प्राप्त कार्यक्रमों ("मैकेनिक्स") द्वारा उपयोग किया जाता है, जो अप्राप्त कार्यक्रमों ("ग्राहक") को सेवा प्रदान करता है। सिस्टम आर्किटेक्चर और बड़ी तस्वीर के लिए पोलकिट मैनुअल पेज देखें।

अपने सहायक कार्यक्रम को क्रियान्वित करने के बजाय, बड़ा, अप्रकाशित कार्यक्रम बस में एक अनुरोध भेजेगा। आपका सहायक या तो एक बूट के रूप में चल सकता है, सिस्टम बूट पर शुरू हुआ, या, बेहतर, सिस्टमड द्वारा आवश्यकतानुसार सक्रिय किया जा सकता है । फिर, वह सहायक यह सत्यापित करने के लिए पोलकिट का उपयोग करेगा कि अनुरोध एक अधिकृत स्थान से आ रहा है। (या, इस मामले में, यदि ऐसा लगता है कि ओवरकिल है, तो आप कुछ अन्य हार्ड-कोडेड प्रमाणीकरण / प्राधिकरण तंत्र का उपयोग कर सकते हैं।)

मुझे डी-बस के माध्यम से संचार करने पर एक अच्छा मूल लेख मिला , और जब मैंने इसका परीक्षण नहीं किया, तो यह मिश्रण में पोलकिट जोड़ने का एक मूल उदाहरण प्रतीत होता है

इस दृष्टिकोण में, कुछ भी निर्धारित नहीं किया जाना चाहिए।


5

ऐसा करने का एक तरीका यह है कि सी में लिखा गया एक सेट्यूइड-रूट प्रोग्राम बनाया जाए जो केवल वही करता है जिसकी आवश्यकता है और अधिक कुछ नहीं। आपके मामले में, इसे किसी भी उपयोगकर्ता इनपुट को देखने की आवश्यकता नहीं है।

#include <unistd.h>
#include <string.h>
#include <stdio.h>  // for perror(3)
// #include ...  more stuff for open(2)

static void write_str_to_file(const char*fn, const char*str) {
    int fd = open(fn, O_WRONLY)
    if (-1 == fd) {
        perror("opening device file");  // make this a CPP macro instead of function so you can use string concat to get the filename into the error msg
        exit(1);
    }
    int err = write(fd, str, strlen(str));
    // ... error check
    err = close(fd);
    // ... error check
}

int main(int argc, char**argv) {
    write_string_to_file("/sys/class/gpio/export", "17");
    write_string_to_file("/sys/class/gpio/gpio17/direction", "out");
    return 0;
}

पर्यावरण चर या किसी भी चीज़ के माध्यम से इसे हटाने का कोई तरीका नहीं है, क्योंकि यह सब कुछ एक युगल सिस्टम कॉल करता है।

नकारात्मक पक्ष: आपको हर सिस्टम कॉल के रिटर्न मूल्य की जांच करनी चाहिए।

अपसाइड: एरर चेकिंग वास्तव में आसान है: यदि कोई त्रुटि है, तो बस perrorऔर जमानत: गैर-शून्य स्थिति के साथ बाहर निकलें। यदि कोई त्रुटि है, तो जांच करें strace। वास्तव में अच्छे त्रुटि संदेश देने के लिए आपको इस कार्यक्रम की आवश्यकता नहीं है।


2
दूसरे की अनुपस्थिति से बचाने के लिए कुछ भी लिखने से पहले मुझे दोनों फाइलें खोलने का प्रलोभन दिया जा सकता है। और मैं इस कार्यक्रम को चला सकता हूं, sudoइसलिए इसे स्वयं सेट करने की आवश्यकता नहीं है। संयोग से, के <fcntl.h>लिए है open()
जोनाथन लेफ्लर

3

सूडो के लिए प्रतिध्वनि के बजाय आशीर्वाद टी ऐसी स्थिति के करीब पहुंचने का एक सामान्य तरीका है जहां आपको रूट परमिट को सीमित करने की आवश्यकता होती है। / Dev / null को पुनर्निर्देशित किसी भी आउटपुट को लीक करने से रोकने के लिए है - टी वही करता है जो आप चाहते हैं।

echo "17" | sudo tee /sys/class/gpio/export > /dev/null
echo "out" | sudo tee /sys/class/gpio/gpio17/direction > /dev/null

5
यदि आप के teeसाथ चलने की अनुमति देते sudoहैं, तो आप किसी भी फ़ाइल को अधिलेखित या संलग्न करने की अनुमति दे रहे हैं (उदाहरण के लिए, /etc/passwd- बस एक नया यूआईडी = 0 खाता जोड़ें)। आप सभी आदेशों को चलाने की अनुमति दे सकते हैं sudo(BTW /etc/sudoers'किसी भी फाइल' के सेट से संबंधित है जिससे इसे ओवरराइट किया जा सकता है sudo tee)
cas

2
जाहिरा तौर पर, आप उन फ़ाइलों को सीमित कर सकते हैं जो teeलिख सकते हैं, जैसा कि एक अलग प्रश्न पर इस उत्तर में वर्णित है । बस सुनिश्चित करें कि आप टिप्पणियों को भी पढ़ते हैं, क्योंकि कुछ लोगों के पास इस्तेमाल किए गए मूल सिंटैक्स के साथ समस्या थी और उस समस्या को हल करने का सुझाव देते हैं।
एलेक्स

1
@alex, हाँ, आप ऐसा कर सकते हैं कि सूडो में किसी भी कमांड के साथ - अनुमेय आर्ग को प्रतिबंधित करें। यदि आप अनुमति देना चाहते हैं teeया जो भी बहुत सारी फ़ाइलों के साथ काम करना चाहते हैं, तो विन्यास बहुत लंबा और जटिल हो सकता है sudo
कास

0

आप एक स्क्रिप्ट बना सकते हैं जो आपके इच्छित कार्य को पूरा करती है। फिर, एक नया उपयोगकर्ता खाता बनाएं जो केवल OpenSSH द्वारा उपयोग की गई कुंजी की आपूर्ति करके लॉग इन कर सकता है।

नोट: किसी के पास कुंजी फ़ाइल होने पर वह स्क्रिप्ट चलाने में सक्षम होगा, इसलिए सुनिश्चित करें कि OpenSSH कुंजी फ़ाइल किसी के द्वारा पढ़ने योग्य नहीं है जिसे आप कार्य करने से रोकना चाहते हैं।

OpenSSH कॉन्फ़िगरेशन में (अधिकृत_की फ़ाइल में), कुंजी निर्दिष्ट करने से पहले, एक कमांड निर्दिष्ट करें (एक स्थान के बाद), जैसा कि इस "उदाहरण" पाठ में वर्णित है:

command="myscript" keydata optionalComment

यह कॉन्फ़िगरेशन विकल्प केवल एक विशिष्ट कमांड को चलाने के लिए उस OpenSSH कुंजी को प्रतिबंधित कर सकता है। अब आपके पास सूडो को अनुमति प्रदान करना है, लेकिन OpenSSH कॉन्फ़िगरेशन उस समाधान का टुकड़ा है जो वास्तव में उस उपयोगकर्ता को क्या करने में सक्षम है / सीमित करने के लिए उपयोग किया जा रहा है, ताकि उपयोगकर्ता अन्य कमांड नहीं चला रहा है। यह भी एक "sudo" कॉन्फ़िगरेशन फ़ाइल के रूप में जटिल नहीं है, इसलिए यदि आप OpenBSD का उपयोग करते हैं या यदि OpenBSD का नया "doas" ("करते हैं") अधिक लोकप्रिय होने लगता है (जो भी ऑपरेटिंग सिस्टम आप उपयोग करते हैं उसके भविष्य के संस्करणों के साथ) , आपको सुडो कॉन्फ़िगरेशन में बहुत जटिलता से चुनौती देने की आवश्यकता नहीं होगी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.