Können Sie ein "hier Dokument" beschaffen?

8

Angenommen, ich habe ein Bash-Skript, das als Konfigurationsdatei für ein anderes Bash-Skript fungiert:

config.sh:

verbose=yes
echo "Malicious code!"
name=test

script.sh:

source config.sh
echo "After sourcing: verbose='$verbose', name='$name'"

Das Problem ist, dass dies nicht sehr sicher ist, da alles, was in config.sh abgelegt ist, ausgeführt wird:

$ ./script.sh
Malicious code!
After sourcing: verbose='yes', name='test'

Um es sicherer zu machen, dachte ich, ich würde Zuweisungsoperationen ausgraben und nur diese ausführen. Ich würde dies erreichen, indem ich sourceein "hier-Dokument" übergebe:

script.sh:

source <<EOF
$(grep -P '^\s*\w+=' test.sh)
EOF
echo "After sourcing: verbose='$verbose', name='$name'"

(Ja, ich weiß, dass der reguläre Ausdruck nicht so stark ist; er ist nur ein Platzhalter.) Leider scheint die Quelle mit den folgenden Dokumenten nicht gut zu spielen:

./script.sh: line 1: source: filename argument required
source: usage: source filename [arguments]
After sourcing: verbose='', name=''

Natürlich könnte ich eine beliebige Anzahl von Dingen tun, um Konfigurationsdaten aus einer Datei zu erhalten, und das ist wahrscheinlich sowieso sicherer.

Aber ich habe immer noch diesen Juckreiz; Ich möchte herausfinden, ob das, was ich versucht habe, funktionieren kann. Irgendwelche Vorschläge?

kevlar1818
quelle
1
Falls dies aus den Antworten nicht klar hervorgeht, besteht Ihr Problem darin, dass ein "hier-Dokument" ( <<EOF) wie eine normale Eingabeweiterleitung ( < file) source < filefunktioniert und nicht funktioniert - es sourcemuss ein Dateinamenargument vorhanden sein. Daher benötigen Sie process substitution ( <(command)), das wie ein Dateinamenargument aussieht.
G-Man sagt 'Reinstate Monica'
Ein Ansatz, der einfach zu sichtbar sicher zu machen: while IFS== read -r var value; do case $var in |*[!0-9A-Z_a-z]*) complain;; *) eval "config_$var=\$value";; esac; done <config(Warnung: getippt in meinem Browser, ! Test es ) Vergessen Sie nicht , keine Variablen zu erlauben den Import wie PATH, IFS... Ein Präfix wie config_ist ein sicherer Ansatz.
Gilles 'SO - hör auf böse zu sein'
+1 Obwohl die externe Kontrolle von Konfigurationsdateien an sich ein Symptom für schwerwiegendere Sicherheitsprobleme sein kann, reicht die Eingabevalidierung allein nicht aus, um sie zu beheben. Dies hätte jedoch neben den Sicherheitsaspekten auch andere Verwendungszwecke.
Thomas Nyman
@ G-Man - Sie benötigen keine Prozessersetzung - was sich von einer Standard-Pipe hauptsächlich dadurch unterscheidet, dass Daten nicht an den Standard eines Prozesses übergeben werden, sondern einem Prozess einen Link zu seinem Standard als Argument übergeben wird, im Allgemeinen in der Form /dev/fd/[num]. Dies zu emulieren ist einfach : 3<<HEREDOC . /dev/fd/3\n*file contents*\nHEREDOC\n. Prozess Substitution in der Regel ist ein Rohr, während Heredocs sind in der Regel die Schale TMPFILES Löschungen vor Gabe sie aus - so dass sie nur als Deskriptoren vorhanden sind . in dashihnen sind Rohre. Der andere große Unterschied ist, dass Sie fd [num]für Heredocs angeben können .
Mikesserv

Antworten:

6

source benötigt einen Dateinamen, Sie können keine Eingabe darauf umleiten.

Auf meinem System konnte ich stattdessen die Prozessersetzung verwenden:

source <( grep = test.sh )

Ersetzen Sie =durch den entsprechenden regulären Ausdruck.

Choroba
quelle
2
heh, und hier ist der bösartige Code:delete --recursively /this/important/dir #=
Glenn Jackman
@glennjackman: Das =war nur ein Platzhalter.
Choroba
Warum nicht einfach einen Link zum Deskriptor geben? Das ist alles, was Ihr Prozess-Sub sowieso tut:3<<HEREDOC . /dev/fd/3\nand so on...
MikeServ
1
@mikeserv: Lesbarkeit vielleicht?
Choroba
Ernsthaft? Sie können es natürlich so nennen, wie Sie möchten - und es ist eine der wenigen Arten von Shell-Strukturen, die sich nicht leicht dem ;Füllen unterwerfen lassen . Darüber hinaus können Sie den Deskriptor explizit benennen und nummerieren, was meiner Meinung nach nicht durch Substitutionen möglich ist. Sie können auch führende Tabs automatisch entfernen lassen - und so kann der Code ziemlich analysiert werden - es sieht in einem Kommentar nicht gut aus, weil ich einen Schrägstrich machen muss und so weiter, aber es hat viel mehr Potenzial - und es ist portabel. Wenn Sie nicht mögen .dot, sollten Sie es alias - es ist sicherer als sourcegewöhnlich.
Mikesserv
8
source <(cat << EOF
A=42
EOF
)
echo $A

Ausgabe:

42
Cyrus
quelle
1

Sie können es direkt eval:

eval "$(grep -P '^\s*\w+=' config.sh)" 
#quotes needed if you want the full content of the file (including newlines etc.)

Die Beschaffung ist im Wesentlichen dasselbe wie:

eval "$(cat file)"   

Beachten Sie jedoch, dass Personen möglicherweise alle Codez-Kinz auf der rechten Seite des Gleichheitszeichens ausführen:

a=$(evil_code_here)
b=`evil_code_here`
c="something" evil_code_here
#etc.

Sie brauchen einen besseren Filter.

PSkocik
quelle