2011-01-10 16 views
12

में सैनिटरी शेल कमांड या सिस्टम कॉल बनाना, मैं एक डिमन बना रहा हूं जो मुझे मेरे सर्वर (प्रबंधन) को प्रबंधित करने में मदद करेगा। वेबमिन ठीक काम करता है, जैसा कि सर्वर पर सिर्फ एक खोल खोलता है, लेकिन मैं यूआई डिज़ाइन से सर्वर ऑपरेशंस को नियंत्रित करने में सक्षम होना चाहता हूं, और उपयोगकर्ताओं को समाप्त करने के लिए कुछ कार्यक्षमता का खुलासा करना चाहता हूं।रूबी

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

def perform 
    system "usermod -p #{@options['shadow']} #{@options['username']}" 
end 

एक सार बताते हैं कि अधिक:

यहाँ एक टुकड़ा है कि मेरी समस्या एक मिसाल है https://gist.github.com/773292

मैं सकारात्मक नहीं कर रहा हूँ अगर ठेठ एस्केपिंग और आदानों की sanitizing इस मामले के लिए पर्याप्त है, और किया जा रहा है एक डिजाइनर, मेरे पास सुरक्षा से संबंधित अनुभव का एक टन नहीं है। मुझे पता है कि यह ऐसा कुछ है जो शायद मेरे लिए स्पष्ट होना चाहिए, लेकिन इसकी नहीं!

मैं कैसे सुनिश्चित कर सकता हूं कि वेब एप्लिकेशन जो क्रियाएं बनाएगा और क्रमबद्ध करेगा, वह खतरनाक पाठ को विशेषाधिकार प्राप्त प्रक्रिया में पारित नहीं कर सकता है जो क्रियाएं प्राप्त करता है?

मदद
एआरबी

उत्तर

17

यह आप की तरह नहीं दिखता के लिए धन्यवाद आप क्या कर रहे के लिए एक कवच की जरूरत है। system के लिए प्रलेखन यहां देखें: http://ruby-doc.org/core/classes/Kernel.html#M001441

आपको system के दूसरे रूप का उपयोग करना चाहिए। आपका उपरोक्त उदाहरण बन जाएगा:

system 'usermod', '-p', @options['shadow'], @options['username'] 

एक अच्छे (IMO) तरीका यह लिखने के लिए:

system *%W(usermod -p #{@options['shadow']} #{@options['username']}) 

तर्क इस तरह से सीधे execve कॉल में पारित कर रहे हैं, तो आप की जरूरत नहीं है स्नीकी शेल चाल के बारे में चिंता करें।

+0

तो, मान लें कि अगर मैंने इस कक्षा का खुलासा किया, तो पूरी तरह से unfiltered (मैं नहीं) एक अंतिम उपयोगकर्ता के लिए, और उन्होंने एक छाया हैश और फिर "उपयोगकर्ता नाम; आरएम-आरएफ /" उपयोगकर्ता नाम के रूप में प्रदान किया - यह नहीं होगा '/' – arbales

+2

सही करने का प्रभाव है। तर्क सीधे निष्पादित कार्यक्रम में पास किए जाते हैं। आप इसे स्वयं से सत्यापित कर सकते हैं। 'Ruby -e 'प्रणाली * डब्ल्यू (ls -l foo; rm -rf /)'' – cam

+0

आह चलने का प्रयास करें, ठीक है। यह सही समझ में आता है। मुझे लगता है कि मेरे पास यह विचार है कि एक आवेदन सुनिश्चित करना सुरक्षित है, स्वाभाविक रूप से कठिन होना चाहिए, सरल चरणों और तथ्यों से कठिन, जैसे कि सब कुछ के लिए एक खतरनाक बढ़त मामला मौजूद है।ऐसा इसलिए है क्योंकि मैंने इसके बारे में बहुत कुछ नहीं पढ़ा/सीखा नहीं है। – arbales

15

तुम सिर्फ बाहर निकलें स्थिति लेकिन यह भी परिणाम आप शायद का उपयोग करना चाहते नहीं की जरूरत है Open3.popen3:

require 'open3' 
stdin, stdout, stderr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username']) 
stdout.gets 
sterr.gets 

अधिक यहाँ जानकारी: Getting output of system() calls in Ruby

2

मैं 'shellwords' मॉड्यूल में रखने का सुझाव देते चाहते हैं । यह स्क्रिप्ट:

require 'shellwords' 
parts = ['echo', "'hello world'; !%& some stuff", 'and another argument'] 
command = Shellwords.shelljoin(parts) 
puts command 
output = `#{ command }` 
puts output 

बच गए पाठ और उम्मीद उत्पादन आउटपुट:

echo \'hello\ world\'\;\ \!\%\&\ some\ stuff and\ another\ argument 
'hello world'; !%& some stuff and another argument 
1

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

विंडोज सिस्टम पर system "dir", "&", "echo", "hi!" आज़माएं। दोनों डीआईआर और गूंज चलाए जाएंगे। इको निश्चित रूप से कुछ भी कम निर्दोष हो सकता है।

0

मुझे पता है कि यह एक पुराना धागा है, लेकिन एक और विकल्प है जिसे हल्के से साइमन हर्लिमैन पर स्पर्श किया गया था।

इस विषय के बारे में बहुत सारी जानकारी नहीं है और मुझे लगता है कि यह दूसरों की ज़रूरत में मदद कर सकता है।

इस उदाहरण हम Open3 जो आप आदेशों तुल्यकालिक या असमकालिक चलाने की क्षमता देता है, और stdout, stderr, बाहर निकलें कोड प्रदान करता है, और पीआईडी ​​ इस्तेमाल करेंगे के लिए

ओपन 3 आपको एक अन्य प्रोग्राम चलाते समय बच्चे की प्रक्रिया के लिए इंतजार करने के लिए stdout, stderr, निकास कोड और थ्रेड तक पहुंच प्रदान करता है। आप प्रोग्राम के विभिन्न तरीकों, रीडायरेक्शन, वर्तमान निर्देशिका इत्यादि को प्रक्रिया के रूप में उसी तरह निर्दिष्ट कर सकते हैं। स्पॉन। (स्रोत: Open3 Docs)

मैंने आउटपुट को CommandStatus ऑब्जेक्ट के रूप में प्रारूपित करना चुना। इसमें हमारे stdout, stderr, pid (कार्यकर्ता धागे में) और exitstatus शामिल हैं।

class Command 
    require 'open3' 

    class CommandStatus 
    @stdout  = nil 
    @stderr  = nil 
    @pid  = nil 
    @exitstatus = nil 

    def initialize(stdout, stderr, process) 
     @stdout  = stdout 
     @stderr  = stderr 
     @pid  = process.pid 
     @exitstatus = process.exitstatus 
    end 

    def stdout 
     @stdout 
    end 

    def stderr 
     @stderr 
    end 

    def exit_status 
     @exitstatus 
    end 

    def pid 
     @pid 
    end 
    end 

    def self.execute(command) 
    command_stdout = nil 
    command_stderr = nil 
    process = Open3.popen3(ENV, command + ';') do |stdin, stdout, stderr, thread| 
     stdin.close 
     stdout_buffer = stdout.read 
     stderr_buffer = stderr.read 
     command_stdout = stdout_buffer if stdout_buffer.length > 0 
     command_stderr = stderr_buffer if stderr_buffer.length > 0 
     thread.value # Wait for Process::Status object to be returned 
    end 
    return CommandStatus.new(command_stdout, command_stderr, process) 
    end 
end 


cmd = Command::execute("echo {1..10}") 

puts "STDOUT: #{cmd.stdout}" 
puts "STDERR: #{cmd.stderr}" 
puts "EXIT: #{cmd.exit_status}" 

STDOUT/ERR बफ़र्स पढ़ते समय, मैं command_stdout = stdout_buffer if stdout_buffer.length > 0 का उपयोग करते हैं command_stdout चर या निर्दिष्ट नहीं की गई नियंत्रित करने के लिए। "" के बजाय आपको nil पास करना चाहिए जब कोई डेटा मौजूद न हो। बाद में डेटा सौंपते समय यह अधिक स्पष्ट है।

आपने शायद मुझे command + ';' का उपयोग करके देखा है। इस का कारण यह Kernel.exec से प्रलेखन (जो क्या popen3 का उपयोग करता है) पर आधारित है:

पहला रूप से स्ट्रिंग (कार्यकारी ("कमांड")) इन सरल नियमों का पालन करती हैं:

  • कोई मेटा वर्ण
  • नहीं खोल आरक्षित शब्द और कोई विशेष निर्मित
  • रूबी आदेश का आह्वान सीधे खोल बिना

आप ";" जोड़कर खोल आमंत्रण को मजबूर कर सकते हैं स्ट्रिंग के लिए;

यह बस एक 'spawn': No such file or directory त्रुटि फेंक अगर आप एक विकृत आदेश पास से एक रूबी से बचाता है ( क्योंकि "" एक मेटा चरित्र है)। इसके बजाए यह सीधे कर्नेल को पास कर देगा जहां त्रुटि को सुदृढ़ रूप से हल किया जाएगा और बिना किसी अपवाद के बजाय एसटीडीईआरआर के रूप में दिखाई देगा।