Wie kann ich SSH-Benutzer nach der Anmeldung auf einen vordefinierten Befehlssatz beschränken?


85

Dies ist eine Idee für eine Sicherheit. Unsere Mitarbeiter haben Zugriff auf einige Befehle auf einem Linux-Server, jedoch nicht auf alle. Sie sollen zB die Möglichkeit haben, auf eine Protokolldatei zuzugreifen ( less logfile) oder verschiedene Befehle zu starten ( shutdown.sh/ run.sh).

Hintergrundinformation:

Alle Mitarbeiter greifen mit demselben Benutzernamen auf den Server zu: Unser Produkt wird mit "normalen" Benutzerberechtigungen ausgeführt, es ist keine "Installation" erforderlich. Entpacken Sie es einfach in Ihrem Benutzerverzeichnis und führen Sie es aus. Wir verwalten mehrere Server, auf denen unsere Anwendung "installiert" ist. Auf jeder Maschine gibt es einen Benutzer johndoe. Unsere Mitarbeiter benötigen manchmal Zugriff auf die Anwendung über die Befehlszeile, um auf Protokolldateien zuzugreifen und diese zu überprüfen oder die Anwendung manuell neu zu starten. Nur einige Personen dürfen vollen Befehlszeilenzugriff haben.

Wir verwenden die ppk-Authentifizierung auf dem Server.

Es wäre großartig, wenn Mitarbeiter1 nur auf die Protokolldatei zugreifen kann und Mitarbeiter2 auch X usw. ausführen kann.

Lösung: Als Lösung verwende ich die commandOption wie in der akzeptierten Antwort angegeben. Ich werde mein eigenes kleines Shell-Skript erstellen, das die einzige Datei ist, die für einige Mitarbeiter ausgeführt werden kann . Das Skript bietet mehrere Befehle, die ausgeführt werden können, aber keine anderen. Ich werde die folgenden Parameter authorized_keysvon wie hier angegeben verwenden :

command="/bin/myscript.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3....o9M9qz4xqGCqGXoJw= user@host

Das ist genug Sicherheit für uns. Danke, Community!


Ist die auf Standard-Linux-ACL-Berechtigungen basierende Sicherheit nicht ausreichend? Welche zusätzlichen Funktionen benötigen Sie?
James Brady

21
Das ist eine schreckliche Idee, Marcel.
Vinko Vrsalovic

13
@Vinko, @PEZ: Ich habe einige Hintergrundinformationen hinzugefügt. Anstatt "dumme Idee" zu sagen, könnten Sie Kommentare mit Wert versehen. Was ist Ihrer Meinung nach eine bessere Idee?
Marcel

8
Ich sehe immer noch keine Entschuldigung dafür, dass mehrere Benutzer denselben Benutzernamen haben.
Eldelshell

3
"Mein eigenes kleines Shell-Skript"? Es klingt ziemlich gefährlich. Wenn Sie kein Experte sind, gibt es wahrscheinlich viele Möglichkeiten, sich der vollen Hülle zu entziehen. Ich würde eher einem gut geschriebenen, debuggten und gepflegten Programm vertrauen (mehrere wurden erwähnt).
Bortzmeyer

Antworten:


68

Sie können Schlüssel auch auf zulässige Befehle beschränken (in der Datei authorized_keys).

Das heißt, der Benutzer würde sich nicht über ssh anmelden und dann einen eingeschränkten Befehlssatz haben, sondern nur diese Befehle über ssh ausführen dürfen (z. B. "ssh somehost bin / showlogfile").


Das sieht interessant aus. Ist es möglich, mehrere Befehle zu definieren?
Marcel

12
Dieser Artikel gibt Ihnen einige Optionen für mehrere Befehle unter Verwendung der Datei authorized_keys: linuxjournal.com/article/8257
Bash

@ rd834 ...: Vielen Dank. Ich denke, das hat mir eine "gute" Lösung gegeben ... (zur Frage hinzugefügt). Ich werde diese Antwort als "richtig" akzeptieren.
Marcel

11
Das O'Reilly SSH-Buch enthält eine hervorragende Erklärung dazu, einschließlich des Zulassens mehrerer Befehle durch Einrichten eines Skripts, das die Umgebungsvariable SSH_ORIGINAL_COMMAND betrachtet. oreilly.com/catalog/sshtdg/chapter/ch08.html
Alex Dupuy

5
Diese Serverfehlerantwort enthält einen guten Tipp zum Zulassen mehrerer Befehle mithilfe der exportierten Variablen SSH_ORIGINAL_COMMAND.
MattBianco

31

sshfolgt der rshTradition, indem das Shell-Programm des Benutzers aus der Kennwortdatei zum Ausführen von Befehlen verwendet wird.

Dies bedeutet, dass wir dies lösen können, ohne die sshKonfiguration in irgendeiner Weise einzubeziehen.

Wenn Sie nicht möchten, dass der Benutzer Shell-Zugriff hat, ersetzen Sie einfach die Shell dieses Benutzers durch ein Skript. Wenn Sie hineinschauen, werden /etc/passwdSie sehen, dass es ein Feld gibt, das jedem Benutzer einen Shell-Befehlsinterpreter zuweist. Das Skript wird sowohl für die interaktive Anmeldung ssh user@host als auch für Befehle als Shell verwendet ssh user@host command arg ....

Hier ist ein Beispiel. Ich habe einen Benutzer erstellt, foodessen Shell ein Skript ist. Das Skript druckt die Nachricht my arguments are:gefolgt von ihren Argumenten (jeweils in einer separaten Zeile und in spitzen Klammern) und wird beendet. Im Log-In-Fall gibt es keine Argumente. Folgendes passiert:

webserver:~# ssh foo@localhost
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.

Wenn der Benutzer versucht, einen Befehl auszuführen, sieht dies folgendermaßen aus:

webserver:~# ssh foo@localhost cat /etc/passwd
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>

Unsere "Shell" erhält einen -cStilaufruf mit dem gesamten Befehl als ein Argument, genauso wie er /bin/shihn erhalten würde.

Wie Sie sehen, können wir das Skript jetzt weiterentwickeln, sodass es den Fall erkennt, wenn es mit einem -cArgument aufgerufen wurde , und dann die Zeichenfolge analysiert (z. B. durch Mustervergleich). Die zulässigen Zeichenfolgen können durch rekursives Aufrufen an die reale Shell übergeben werden /bin/bash -c <string>. Der Ablehnungsfall kann eine Fehlermeldung drucken und beenden (einschließlich des Falls, wenn er -cfehlt).

Sie müssen vorsichtig sein, wie Sie dies schreiben. Ich empfehle, nur positive Übereinstimmungen zu schreiben, die nur sehr spezifische Dinge zulassen, und alles andere zu verbieten.

Hinweis: Wenn rootdies der Fall ist , können Sie sich weiterhin bei diesem Konto anmelden, indem Sie die Shell im suBefehl wie folgt überschreiben su -s /bin/bash foo. (Ersatzschale Ihrer Wahl.) Nicht-Root kann dies nicht.

Hier ist ein Beispielskript: Beschränken Sie den Benutzer darauf, nur sshfür den gitZugriff auf Repositorys unter zu verwenden /git.

#!/bin/sh

if [ $# -ne 2 ] || [ "$1" != "-c" ] ; then
  printf "interactive login not permitted\n"
  exit 1
fi

set -- $2

if [ $# != 2 ] ; then
  printf "wrong number of arguments\n"
  exit 1
fi

case "$1" in
  ( git-upload-pack | git-receive-pack )
    ;; # continue execution
  ( * )
    printf "command not allowed\n"
    exit 1
    ;;
esac

# Canonicalize the path name: we don't want escape out of
# git via ../ path components.

gitpath=$(readlink -f "$2")  # GNU Coreutils specific

case "$gitpath" in
  ( /git/* )
     ;; # continue execution
  ( * )
    printf "access denied outside of /git\n"
    exit 1
    ;;
esac

if ! [ -e "$gitpath" ] ; then
   printf "that git repo doesn't exist\n"
   exit 1
fi

"$1" "$gitpath"

Natürlich vertrauen wir , dass diese Programme Git git-upload-packund git-receive-packhaben keine Löcher oder Luken zu entkommen , die Benutzer Zugriff auf das System erhalten.

Dies ist mit dieser Art von Beschränkungsschema verbunden. Der Benutzer ist authentifiziert, um Code in einer bestimmten Sicherheitsdomäne auszuführen, und wir beschränken uns darauf, diese Domäne auf eine Unterdomäne zu beschränken. Wenn Sie beispielsweise einem Benutzer erlauben, den vimBefehl für eine bestimmte Datei auszuführen , um sie zu bearbeiten, kann der Benutzer einfach eine Shell mit abrufen :!sh[Enter].


5
Im Ernst, das ist sehr gefährlich. Was hindert mich an der Ausführung git-receive-pack '/git/';dd if=/dev/urandom of=/dev/sda?
Yeti

@ Yeti Haben wir hier ein Befehlsinjektionsloch? Das muss angegangen werden. Außerdem casesieht der Missbrauch von Dateimustern, den ich in der Datei begangen habe, für mich nicht korrekt aus.
Kaz

1
Ja, /bin/bash -c "$2"ist unsicher (ähnlich wie SQL Injection funktioniert). Sie können den String mit "magischen Anführungszeichen" wie PHP filtern. Die einfache Möglichkeit, die Sicherheit absolut zu gewährleisten, besteht darin, einen Befehl manuell aufzurufen und die Parameter dann in doppelte Anführungszeichen zu setzen. Weil die Sicherheit des Ganzen dann davon abhängt, dass dieser Befehl das schwächste Glied ist (schwerer zu überprüfen). Am interessantesten zu sehen, wie Ihre Antwort 22 positive Stimmen hat, aber niemand hat dies bemerkt;) Werden Sie Ihre eigene Antwort aktualisieren?
Yeti

1
@ Yeti Ja; Ich habe es gerade getan. Ich habe das Skript durch eines ersetzt, das das Argument -c durchbricht setund dann nur die ersten beiden Wörter daraus entnimmt. Der erste muss ein zulässiger git-Befehl sein, und der zweite muss ein Pfad sein, der kanonisiert, mit dem zulässigen Präfix verglichen und auch auf Existenz geprüft wird. Können Sie sich eine Möglichkeit vorstellen, dies zu brechen?
Kaz

1
Wenn nicht jemand einen Alias ​​für einen der angegebenen Befehle erstellt (oder einen Befehl überschreibt), sollten Bash-Anführungszeichen sicher sein (und wenn nicht, ist dies ein Fehler in Bash).
Yeti

15

Was Sie suchen, heißt Restricted Shell . Bash bietet einen solchen Modus, in dem Benutzer nur Befehle ausführen können, die in ihren Ausgangsverzeichnissen vorhanden sind (und sie können nicht in andere Verzeichnisse wechseln), was für Sie möglicherweise gut genug ist.

Ich habe festgestellt, dass dieser Thread sehr anschaulich ist, wenn auch etwas veraltet.


1
Was ist, wenn der Benutzer "! / Bin / sh" oder ähnliches von der weniger Eingabeaufforderung aus tut?
PEZ

3
@Ubersoldat: Bitte wachsen Sie auf und mildern Sie die Aggression in all Ihren Posts. Er fragte, ob die Einschränkung auch nur für Bash- oder Child-Prozesse gilt (und um seine Frage zu beantworten, stellt sich heraus, dass dies nicht der Fall ist).

Ein Hauptproblem bei eingeschränkten Shells besteht darin, dass Sie zum Sichern den Pfad verwenden müssen, um den Pfad einzuschränken, integrierte Funktionen zu deaktivieren usw. Diese Dateien müssen jedoch nur für interaktive Shells aufgerufen werden. Wenn ein Benutzer ssh verwendet, um einen Remote-Befehl auszuführen, wird er nicht aufgerufen. Dies ermöglicht einem Benutzer mit ssh-Zugriff auf ein Konto mit SHELL = / bin / rbash, einfach so etwas wie "ssh remotehost bash" auszuführen, um eine nicht interaktive, aber uneingeschränkte Shell zu erhalten. Sie benötigen erzwungene SSH-Befehle, wie von HD vorgeschlagen, dies kann jedoch vor Shell-Escape-Aktionen schützen, wenn PEZ dazu aufgefordert wird (sobald PATH gesperrt ist, enthält es standardmäßig / bin: / usr / bin).
Alex Dupuy

2
Ich nehme das zurück, bash wird aufrufen Bashrc (nicht .profile) , wenn nicht interaktiv unter sshd läuft; Sie müssen jedoch sicherstellen, dass Sie PATH explizit festlegen und eingebaute und Aliase in .bashrc deaktivieren. Ein Wechsel in ein Unterverzeichnis, das nicht in / über PATH oder .ssh / oder .bashrc liegt, ist ebenfalls eine gute Idee. Ein Befehl, der in beliebige Dateien schreiben kann, führt zu einem Problem. Diese sind nicht immer offensichtlich. Beispielsweise kann der Befehl sed 'w' zum Überschreiben von .bashrc und zum Ausbrechen verwendet werden. Ein Chroot-Gefängnis ist immer sicherer, wenn Sie es verwenden können, und erzwungene SSH-Befehle sind eingeschränkter.
Alex Dupuy

4

Sie sollten "rssh", die eingeschränkte Shell, erwerben

Sie können den oben genannten Richtlinien für Einschränkungen folgen. Sie sind alle ziemlich selbsterklärend und einfach zu befolgen. Verstehen Sie die Begriffe "chroot jail" und wie Sie sshd / terminal-Konfigurationen effektiv implementieren und so weiter.

Da die meisten Ihrer Benutzer über sshd auf Ihre Terminals zugreifen, sollten Sie wahrscheinlich auch in sshd_conifg, der Konfigurationsdatei des SSH-Dämons, nachsehen, um bestimmte Einschränkungen über SSH anzuwenden. Seien Sie jedoch vorsichtig. Verstehe richtig, was du zu implementieren versuchst, denn die Auswirkungen falscher Konfigurationen sind wahrscheinlich ziemlich schlimm.


1
Beachten Sie, dass pizzashack.org/rssh eine ausgezeichnete (möglicherweise die beste) Lösung für den Sonderfall ist, in dem Sie scp / sftp / rdist / rsync / cvs zulassen möchten (und keinen Zugriff auf etwas außerhalb eines Chroot-Gefängnisses benötigen) Es löst nicht die allgemeine Frage des Originalplakats, wonach Benutzer Protokolldateien anzeigen und bestimmte Skripts zum Ausführen / Herunterfahren ausführen können sollen.
Alex Dupuy

2
rsshwurde von Debian Buster entfernt. Ich denke, die neue Schärfe ist GNU Rush .
Thomas

1
@Thomas Ich glaube, rssh ist jetzt nicht mehr gewartet und hat ein bekanntes Sicherheitsproblem: sourceforge.net/p/rssh/mailman/message/36519118
Max Barraclough

4

Warum schreibst du nicht deine eigene Login-Shell? Es wäre ziemlich einfach, Bash dafür zu verwenden, aber Sie können jede Sprache verwenden.

Beispiel in Bash

Verwenden Sie Ihren bevorzugten Editor, um die Datei zu erstellen /root/rbash.sh (dies kann ein beliebiger Name oder Pfad sein, sollte aber sein chown root:rootund chmod 700):

#!/bin/bash

commands=("man" "pwd" "ls" "whoami")
timestamp(){ date +'%Y-%m-%s %H:%M:%S'; }
log(){ echo -e "$(timestamp)\t$1\t$(whoami)\t$2" > /var/log/rbash.log; }
trycmd()
{
    # Provide an option to exit the shell
    if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
    then
        exit
        
    # You can do exact string matching for some alias:
    elif [[ "$ln" == "help" ]]
    then
        echo "Type exit or q to quit."
        echo "Commands you can use:"
        echo "  help"
        echo "  echo"
        echo "${commands[@]}" | tr ' ' '\n' | awk '{print "  " $0}'
    
    # You can use custom regular expression matching:
    elif [[ "$ln" =~ ^echo\ .*$ ]]
    then
        ln="${ln:5}"
        echo "$ln" # Beware, these double quotes are important to prevent malicious injection
        
        # For example, optionally you can log this command
        log COMMAND "echo $ln"
    
    # Or you could even check an array of commands:
    else
        ok=false
        for cmd in "${commands[@]}"
        do
            if [[ "$cmd" == "$ln" ]]
            then
                ok=true
            fi
        done
        if $ok
        then
            $ln
        else
            log DENIED "$cmd"
        fi
    fi
}

# Optionally show a friendly welcome-message with instructions since it is a custom shell
echo "$(timestamp) Welcome, $(whoami). Type 'help' for information."

# Optionally log the login
log LOGIN "$@"

# Optionally log the logout
trap "trap=\"\";log LOGOUT;exit" EXIT

# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user@host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
    shift
    trycmd "$@"
else
    while echo -n "> " && read ln
    do
        trycmd "$ln"
    done
fi

Sie müssen diese ausführbare Datei lediglich als Anmeldeshell festlegen. Bearbeiten Sie beispielsweise Ihre /etc/passwdDatei und ersetzen Sie Ihre aktuelle Anmeldeshell dieses Benutzers /bin/bashdurch /root/rbash.sh.

Dies ist nur ein einfaches Beispiel, aber Sie können es so weit fortgeschritten machen, wie Sie möchten. Die Idee ist da. Achten Sie darauf, sich nicht auszusperren, indem Sie die Login-Shell Ihres eigenen und einzigen Benutzers ändern. Und testen Sie immer seltsame Symbole und Befehle, um festzustellen, ob sie tatsächlich sicher sind.

Sie können es testen mit : su -s /root/rbash.sh.

Passen Sie auf , stellen Sie sicher, dass der gesamte Befehl übereinstimmt, und gehen Sie vorsichtig mit Platzhaltern um! Besser ausschließen Bash-Symbole wie ;, &, &&, ||,$ , und Backticks sicher zu sein.

Abhängig von der Freiheit, die Sie dem Benutzer geben, wird es nicht viel sicherer. Ich habe festgestellt, dass ich oft nur einen Benutzer erstellen musste, der nur auf wenige relevante Befehle zugreifen kann, und in diesem Fall ist dies wirklich die bessere Lösung. Möchten Sie jedoch mehr Freiheit geben, sind ein Gefängnis und Berechtigungen möglicherweise angemessener. Fehler werden leicht gemacht und erst bemerkt, wenn es schon zu spät ist.


Dieser Ansatz hat mir sehr gut gefallen. Haben Sie eine Idee, wie wir mit Mehrwortbefehlen wie "service httpd restart" umgehen können?
Farzan

2
@Farzan Sie können Befehle in einer Variablen ausführen, z . B ln="service httpd restart".: ${ln[@]}. Denken Sie dennoch an Sicherheitsprobleme. In einem solchen Fall wäre eine Whitelist nur für alphanumerische Zeichen und Leerzeichen hilfreich. Sie können aber auch einfach: if [[ "$ln" == "restart-httpd"];then service httpd restart;fiund mit solchen einfachen Befehlen arbeiten.
Yeti

/root/rbash.sh: Permission denied Ich habe auch versucht, chmod 777
Christian

@Christian, haben fügen Sie /root/rbash.shzu /etc/shells? Das hängt von der Verteilung ab. Sie können auch versuchen selinux, die Nachrichten vorübergehend zu deaktivieren und die Protokollmeldungen auf Hinweise (siehe Zeitstempel) in den Dateien in zu überprüfen /var/log.
Yeti

@yeti nein, wurde erklärt, um / root hinzuzufügen :) Ich werde es jetzt versuchen.
Christian


1

GNU Rush ist möglicherweise der flexibelste und sicherste Weg, dies zu erreichen:

GNU Rush ist eine eingeschränkte Benutzer-Shell, die für Websites entwickelt wurde, die nur eingeschränkten Remotezugriff auf ihre Ressourcen bieten, z. B. SVN- oder Git-Repositorys, SCP oder dergleichen. Mithilfe einer ausgeklügelten Konfigurationsdatei können Sie mit GNU Rush die Befehlszeilen, die Benutzer ausführen, sowie die Verwendung von Systemressourcen wie virtuellem Speicher, CPU-Zeit usw. vollständig steuern.


0

Eine andere Sichtweise ist die Verwendung von POSIX-ACLs. Sie müssen von Ihrem Dateisystem unterstützt werden. Sie können jedoch alle Befehle unter Linux genau so optimieren, wie Sie es unter Windows tun (nur ohne die schönere Benutzeroberfläche) ). Verknüpfung

Eine andere Sache, die Sie prüfen sollten, ist PolicyKit .

Sie müssen einiges googeln, um alles zum Laufen zu bringen, da dies im Moment definitiv keine Stärke von Linux ist.


0

[Offenlegung: Ich habe sshdo geschrieben, das unten beschrieben wird]

Wenn Sie möchten, dass die Anmeldung interaktiv ist, ist das Einrichten einer eingeschränkten Shell wahrscheinlich die richtige Antwort. Wenn es jedoch einen tatsächlichen Befehlssatz gibt, den Sie zulassen möchten (und sonst nichts), und es in Ordnung ist, diese Befehle einzeln über ssh auszuführen (z. B. ssh user @ host cmd arg bla bla), dann ein generisches Befehls-Whitelist-Steuerelement für SSH könnte das sein, was Sie brauchen. Dies ist nützlich, wenn die Befehle auf Client-Seite in Skripten geschrieben sind und der Benutzer den Befehl ssh nicht tatsächlich eingeben muss.

Dafür gibt es ein Programm namens sshdo. Es steuert, welche Befehle über eingehende SSH-Verbindungen ausgeführt werden dürfen. Es steht zum Download zur Verfügung unter:

http://raf.org/sshdo/ (Handbuchseiten hier lesen) https://github.com/raforg/sshdo/

Es verfügt über einen Trainingsmodus, in dem alle versuchten Befehle zugelassen werden, und eine Option --learn, um die Konfiguration zu erstellen, die erforderlich ist, um gelernte Befehle dauerhaft zuzulassen. Dann kann der Trainingsmodus ausgeschaltet werden und andere Befehle werden nicht ausgeführt.

Es gibt auch die Option --unlearn, um das Zulassen von Befehlen zu beenden, die nicht mehr verwendet werden, um die strengsten Berechtigungen beizubehalten, wenn sich die Anforderungen im Laufe der Zeit ändern.

Es ist sehr pingelig, was es erlaubt. Ein Befehl mit Argumenten wird nicht zugelassen. Es können nur vollständige Shell-Befehle zugelassen werden.

Es werden jedoch einfache Muster unterstützt, um ähnliche Befehle darzustellen, die sich nur in den Ziffern unterscheiden, die in der Befehlszeile angezeigt werden (z. B. Sequenznummern oder Datums- / Zeitstempel).

Es ist wie eine Firewall oder ein Whitelisting-Steuerelement für SSH-Befehle.

Und es unterstützt verschiedene Befehle, die für verschiedene Benutzer zulässig sind.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.