SSH kullanıcıları, oturum açtıktan sonra önceden tanımlanmış bir komut setiyle nasıl kısıtlanır?


88

Bu bir güvenlik fikri. Çalışanlarımız bir linux sunucusundaki bazı komutlara erişebilir ancak hepsine değil. Örneğin, bir günlük dosyasına ( less logfile) erişme veya farklı komutlar başlatma ( shutdown.sh/ run.sh) olasılığına sahip olmalıdırlar .

Arkaplan bilgisi:

Tüm çalışanlar sunucuya aynı kullanıcı adıyla erişir: Ürünümüz "normal" kullanıcı izinleriyle çalışır, "kurulum" gerekmez. Sadece kullanıcı dizininize açın ve çalıştırın. Uygulamamızın "kurulu" olduğu birkaç sunucuyu yönetiyoruz. Her makinede bir kullanıcı vardır johndoe. Çalışanlarımızın bazen günlük dosyalarına erişmek ve bunları kontrol etmek veya uygulamayı elle yeniden başlatmak için komut satırından uygulamaya erişmeleri gerekir. Yalnızca bazı kişiler tam komut satırı erişimine sahip olabilir.

Sunucuda ppk kimlik doğrulaması kullanıyoruz.

Çalışan1'in yalnızca günlük dosyasına erişebilmesi ve çalışan2'nin de X vb. Yapabilmesi harika olurdu ...

Çözüm: Çözümcommand olarak , seçeneği kabul edilen cevapta belirtildiği gibi kullanacağım . Bazı çalışanlar için yürütülebilecek tek dosya olacak kendi küçük kabuk betiğimi yapacağım . Komut dosyası, çalıştırılabilen birkaç komut sunacak, ancak diğerleri sunmayacaktır. Aşağıdaki parametreleri buradaauthorized_keys belirtildiği gibi kullanacağım :

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

Bu bizim için yeterli güvenlik. Teşekkürler, topluluk!


Standart Linux ACL izin tabanlı güvenlik yeterli değil mi? Hangi ekstra özelliklere ihtiyacınız var?
James Brady

22
Bu berbat bir fikir, Marcel.
Vinko Vrsalovic

14
@Vinko, @PEZ: Bazı arka plan bilgileri ekledim. "Aptal fikir" demek yerine, değerli yorumlar sunabilirsiniz. Sizce daha iyi fikir nedir?
Marcel

8
Hala birden fazla kullanıcının aynı kullanıcı adını paylaşması konusunda herhangi bir mazeret göremiyorum.
Eldelshell

3
"Kendi küçük kabuk betiğim" mi? Kulağa oldukça tehlikeli geliyor. Uzman değilseniz, muhtemelen ondan tam kabuğa kaçmanın birçok yolu vardır. İyi yazılmış, hata ayıklaması yapılmış ve bakımı yapılmış bir programa güvenmeyi tercih ederim (birkaçından söz edildi).
bortzmeyer

Yanıtlar:


69

Ayrıca, anahtarları izin verilen komutlarla da sınırlayabilirsiniz (yetkili_keys dosyasında).

Yani, kullanıcı ssh aracılığıyla oturum açmaz ve daha sonra kısıtlı bir komut setine sahip olmaz, bunun yerine yalnızca bu komutları ssh aracılığıyla yürütmesine izin verilir (örneğin, "ssh bir şekilde bin / showlogfile")


Bu ilginç görünüyor. Birden fazla komut tanımlamak mümkün mü?
Marcel

12
Bu makale, authred_keys
Bash

@ rd834 ...: Çok teşekkürler. Sanırım bu bana "iyi" bir çözüm verdi ... (soruya eklendi). Bu cevabı "doğru" olarak kabul edeceğim.
Marcel

11
O'Reilly SSH kitabının, SSH_ORIGINAL_COMMAND ortam değişkenine bakan bir komut dosyası kurarak birden çok komuta izin vermek dahil, bunun nasıl yapılacağına dair mükemmel bir açıklaması vardır. oreilly.com/catalog/sshtdg/chapter/ch08.html
Alex Dupuy

5
bu serverfault yanıtı , dışa aktarılan SSH_ORIGINAL_COMMAND değişkenini kullanarak birden çok komuta nasıl izin verileceğine dair güzel bir ipucu içerir.
MattBianco

33

sshbu rshgeleneği, komutları yürütmek için parola dosyasından kullanıcının kabuk programını kullanarak izler .

Bu ssh, herhangi bir şekilde yapılandırmaya dahil olmadan bunu çözebileceğimiz anlamına gelir .

Kullanıcının kabuk erişimine sahip olmasını istemiyorsanız, o kullanıcının kabuğunu bir komut dosyasıyla değiştirin. İçeri bakarsanız, /etc/passwdher kullanıcıya bir kabuk komut yorumlayıcısı atayan bir alan olduğunu göreceksiniz. Komut dosyası, hem etkileşimli oturum açma ssh user@host hem de komutlar için kabuk olarak kullanılır ssh user@host command arg ....

İşte bir örnek. fooKabuğu betik olan bir kullanıcı oluşturdum . Komut dosyası, mesajın my arguments are:ardından argümanlarını (her biri ayrı bir satırda ve köşeli parantez içinde) yazdırır ve sona erer. Durumda günlükte hiçbir argüman yoktur. İşte olanlar:

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

Kullanıcı bir komutu çalıştırmayı denerse, şöyle görünür:

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

"Kabuğumuz" -c, tüm komutun tek bir argüman olarak olduğu bir stil çağrısı alır , tıpkı /bin/shonu alacak gibi.

Gördüğünüz gibi, şimdi yapabileceğimiz şey, komut dosyasını daha da geliştirmektir, böylece bir -cargümanla çağrıldığında durumu tanır ve sonra dizeyi ayrıştırır (örneğin desen eşleştirerek). İzin verilen dizeler özyinelemeli olarak çağrılarak gerçek kabuğa geçirilebilir /bin/bash -c <string>. Red durumu, bir hata mesajı yazdırabilir ve sona erebilir ( -ceksik olduğu durum dahil ).

Bunu nasıl yazdığına dikkat etmelisin. Yalnızca çok özel şeylere izin veren ve diğer her şeye izin vermeyen pozitif eşleşmeler yazmanızı öneririm.

Not: Eğer rootöyleyseniz su, bunun gibi komuttaki kabuğu geçersiz kılarak bu hesaba yine de giriş yapabilirsiniz su -s /bin/bash foo. (Yedek kabuk seçimi.) Kök olmayanlar bunu yapamaz.

İşte bir örnek script: Sadece kullanarak kullanıcıyı kısıtlamak sshiçin gitaltında havuzlarına erişim /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"

Tabii ki, bu Git programlarının git-upload-packve git-receive-packkullanıcıların sisteme erişimini sağlayacak delikler veya kaçış kapakları olmadığına güveniyoruz .

Bu, bu tür bir kısıtlama planının doğasında vardır. Kullanıcının, belirli bir güvenlik etki alanında kod yürütmesi için kimliği doğrulanır ve bu etki alanını bir alt etki alanıyla sınırlamak için bir kısıtlama getiriyoruz. Örneğin, bir kullanıcının vimdüzenlemesi için belirli bir dosya üzerinde komutu çalıştırmasına izin verirseniz , kullanıcı sadece bir kabuk alabilir :!sh[Enter].


6
Cidden, bu ÇOK TEHLİKELİ. Yürütmekten beni ne alıkoyacak git-receive-pack '/git/';dd if=/dev/urandom of=/dev/sda?
Yeti

@Yeti Burada bir komut enjeksiyon deliğimiz var mı? Bunun ele alınması gerekiyor. Ayrıca, içinde yaptığım dosya kalıplarının kötüye kullanılması casebana doğru görünmüyor.
Kaz

1
Evet, /bin/bash -c "$2"güvensizdir (SQL enjeksiyonunun çalışmasına benzer). Dizeyi PHP gibi "sihirli tırnaklar" ile filtreleyebilirsiniz. Ancak güvenliği kesin olarak sağlamanın kolay yolu, bir komutu manuel olarak çağırmak ve ardından parametreleri çift tırnak içinde iletmektir. Çünkü her şeyin güvenliği bu komutun en zayıf bağlantı olmasına bağlıdır (doğrulanması daha zordur). Cevabınızın 22 olumlu oyu olduğunu görmek en ilginç, ama bunu kimse fark etmedi;) Kendi cevabınızı güncelleyecek misiniz?
Yeti

1
@Yeti Evet; Az önce yaptım. Komut dosyasını -c argümanını kıran setve sonra sadece ilk iki kelimeyi alan bir komut dosyasıyla değiştirdim . İlki izin verilen bir git-komut, ikincisi ise kanonikleştirilmiş, izin verilen öneke göre kontrol edilen ve ayrıca var olup olmadığı kontrol edilen bir yol olmalıdır. Bunu kırmanın herhangi bir yolunu düşünebiliyor musun?
Kaz

1
Birisi verilen komutlardan herhangi biri için bir takma ad oluşturmadıkça (veya bir komutu geçersiz kılmadıkça), o zaman hayır, Bash çift tırnakları güvenli olmalıdır (ve değilse, bu Bash'de bir hatadır).
Yeti

15

Aradığınız şeyin adı Sınırlı Kabuk . Bash, kullanıcıların yalnızca kendi ana dizinlerinde bulunan komutları çalıştırabilecekleri (ve diğer dizinlere geçemeyecekleri), sizin için yeterince iyi olabilecek bir mod sağlar.

Bu konuyu biraz tarihli ise çok açıklayıcı buldum .


1
Ya kullanıcı "! / Bin / sh" veya benzerini daha az istemden yaparsa?
PEZ

3
@Ubersoldat: Lütfen tüm gönderilerinizde büyüyün ve saldırganlığı azaltın. Kısıtlamanın sadece bash veya çocuk süreçleri için de geçerli olup olmadığını soruyordu (ve sorusuna cevap vermek gerekirse öyle değil).

Kısıtlı kabuğun en büyük problemi, onu güvenceye almak için PATH'yi kısıtlamak, yerleşikleri devre dışı bırakmak, vb. İçin .profile veya .bashrc kullanmanız gerektiğidir, ancak bu dosyalar yalnızca etkileşimli kabuklar için çağrılır. Bir kullanıcı uzak bir komutu çalıştırmak için ssh kullanırsa, bunlar çağrılmaz. Bu, SHELL = / bin / rbash ile bir hesaba ssh erişimi olan bir kullanıcının etkileşimli olmayan ancak kısıtlanmamış bir kabuk elde etmek için "ssh remotehost bash" gibi bir şey yapmasına izin verir. HD'nin önerdiği gibi SSH zorlamalı komutlara ihtiyacınız vardır, ancak bu, PEZ'nin sorulduğu şekilde kabuk kaçışlarına karşı koruma sağlayabilir (PATH kilitlendiğinde - varsayılan olarak / bin: / usr / bin içerir).
Alex Dupuy

2
Bunu geri almak, bash edecek sshd altında olmayan etkileşimli çalıştırırken (değil .profile) Bashrc çağırmak; ancak, PATH'i açıkça ayarladığınızdan ve .bashrc'deki yerleşikleri ve diğer adları devre dışı bıraktığınızdan emin olmalısınız - PATH veya .ssh / veya .bashrc içinde / üstünde olmayan bir alt dizine geçmek de iyi bir fikirdir. Rasgele dosyalara yazabilen herhangi bir komuta sahip olmak bir sorun yaratacaktır - bunlar her zaman açık değildir, örneğin sed 'w' komutu .bashrc'nin üzerine yazmak ve kırmak için kullanılabilir. Bir chroot hapsi, onu kullanabilirseniz her zaman daha güvenli olacaktır ve ssh zorunlu komutları daha kısıtlı olacaktır.
Alex Dupuy

5

Neden kendi giriş kabuğunuzu yazmıyorsunuz? Bunun için Bash'i kullanmak oldukça basit olacaktır, ancak herhangi bir dili kullanabilirsiniz.

Bash'de Örnek

Dosyayı oluşturmak için favori düzenleyicinizi kullanın /root/rbash.sh(bu herhangi bir ad veya yol olabilir, ancak chown root:rootve olmalıdır 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

Tek yapmanız gereken, bu yürütülebilir dosyayı oturum açma kabuğunuz olarak ayarlamaktır. Örneğin, /etc/passwddosyanızı düzenleyin ve o kullanıcının mevcut oturum açma kabuğunuzu /bin/bashile değiştirin /root/rbash.sh.

Bu sadece basit bir örnek, ancak istediğiniz kadar ilerletebilirsiniz, fikir orada. Kendi ve tek kullanıcınızın oturum açma kabuğunu değiştirerek kendinizi kilitlememeye dikkat edin. Ve gerçekten güvenli olup olmadığını görmek için her zaman garip sembolleri ve komutları test edin.

Sen ile test edebilirsiniz: su -s /root/rbash.sh.

Dikkat edin , tüm komutu eşleştirdiğinizden emin olun ve joker karakterlere dikkat edin! Daha iyi gibi Bash-semboller hariç ;, &, &&, ||, $, ve backticks emin olmak için.

Kullanıcıya verdiğiniz özgürlüğe bağlı olarak bundan daha güvenli olamaz. Çoğu zaman, yalnızca birkaç ilgili komuta erişimi olan bir kullanıcı yapmam gerektiğini fark ettim ve bu durumda bu gerçekten daha iyi bir çözümdür. Ancak, daha fazla özgürlük vermek istiyor musunuz, hapishane ve izinler daha uygun olabilir. Hatalar kolayca yapılır ve yalnızca çok geç olduğunda fark edilir.


Bu yaklaşımı gerçekten beğendim. "Httpd yeniden başlatma hizmeti" gibi çok kelimeli komutları nasıl işleyebileceğimiz konusunda bir fikriniz var mı?
Farzan

2
Sen mesela, bir değişkene komutları yürütebilirsiniz @Farzan ln="service httpd restart"ile: ${ln[@]}. Yine de güvenlik sorunlarını düşündüğünüzden emin olun, yalnızca alfasayısal karakterler ve beyaz boşluklar için bir beyaz liste böyle bir durumda yararlı olacaktır. Ancak şunları da yapabilirsiniz: if [[ "$ln" == "restart-httpd"];then service httpd restart;five bunun gibi basit komutlarla çalışın.
Yeti

/root/rbash.sh: Permission denied Chmod 777'yi de denedim
Christian

@Christian, sen ekledin /root/rbash.shiçin /etc/shells? Dağıtıma bağlıdır. Ayrıca geçici olarak devre dışı bırakmayı deneyebilir selinuxve içindeki dosyalardaki ipuçları için günlük mesajlarını kontrol edebilirsiniz (zaman damgasına bakın) /var/log.
Yeti

@yeti no, / root eklenmesi açıklandı :) Şimdi deneyeceğim.
Christian

4

Kısıtlanmış kabuk olan "rssh" yi edinmelisiniz

Yukarıda belirtilen kısıtlama kılavuzlarını takip edebilirsiniz, hepsi oldukça açıklayıcıdır ve takip etmesi kolaydır. `` Chroot hapishanesi '' terimlerini ve sshd / terminal yapılandırmalarının nasıl etkin bir şekilde uygulanacağını vb. Anlayın.

Kullanıcılarınızın çoğu terminallerinize sshd aracılığıyla eriştiğinden, SSH aracılığıyla belirli kısıtlamaları uygulamak için muhtemelen SSH arka plan programı yapılandırma dosyası olan sshd_conifg'ye de bakmalısınız. Ancak dikkatli olun. Neyi uygulamaya çalıştığınızı doğru bir şekilde anlayın, çünkü yanlış yapılandırmaların sonuçları muhtemelen oldukça korkunçtur.


1
Not o pizzashack.org/rssh mükemmel izin vermek istediğiniz özel durum için (muhtemelen en iyi) çözümdür scp / sftp / rdist / rsync / cvs (ve chroot hapse dışında herhangi bir şeyin erişimine gerek yoktur) - ancak , kullanıcıların günlük dosyalarını görüntüleyebilmelerini ve belirli çalıştırma / kapatma komut dosyalarını çalıştırabilmelerini isteyen orijinal göndericinin genel sorusunu çözmez.
Alex Dupuy

2
rsshDebian Buster'dan kaldırıldı. Bence yeni ateş GNU telaşı .
Thomas

1
@Thomas, rssh'nin artık bakımsız olduğuna ve bilinen bir güvenlik sorunu olduğuna inanıyorum: sourceforge.net/p/rssh/mailman/message/36519118
Max Barraclough

2

GNU Rush , bunu başarmanın en esnek ve güvenli yolu olabilir:

GNU Rush, svn veya git depoları, scp veya benzeri gibi kaynaklarına sınırlı uzaktan erişim sağlayan siteler için tasarlanmış bir Sınırlı Kullanıcı Kabuğu'dur. Gelişmiş bir yapılandırma dosyası kullanan GNU Rush, kullanıcıların yürüttüğü komut satırlarının yanı sıra sanal bellek, CPU zamanı vb. Gibi sistem kaynaklarının kullanımı üzerinde tam kontrol sağlar.



0

Buna bakmanın başka bir yolu da POSIX ACL'leri kullanmaktır, dosya sisteminiz tarafından desteklenmesi gerekir, ancak Linux'taki tüm komutların ince ayarını, Windows'ta aynı kontrole sahip olduğunuz gibi (sadece daha güzel kullanıcı arayüzü olmadan) yapabilirsiniz. ). bağlantı

İncelenmesi gereken diğer bir konu ise PolicyKit .

Her şeyin çalışması için epeyce googling yapmanız gerekecek çünkü bu şu anda kesinlikle Linux'un bir gücü değil.


0

[Açıklama: Aşağıda açıklanan sshdo yazdım]

Girişin etkileşimli olmasını istiyorsanız, kısıtlı bir kabuk oluşturmak muhtemelen doğru cevaptır. Ancak izin vermek istediğiniz gerçek bir komut seti varsa (ve başka hiçbir şey yoksa) ve bu komutların ssh aracılığıyla ayrı ayrı çalıştırılması uygunsa (örneğin, ssh user @ host cmd arg blah blah), o zaman için genel bir komut beyaz listeye alma kontrolü ssh ihtiyacınız olan şey olabilir. Bu, komutlar bir şekilde istemci tarafında yazıldığında ve kullanıcının gerçekten ssh komutunu yazmasını gerektirmediğinde kullanışlıdır.

Bunu yapmak için sshdo adında bir program var. Gelen ssh bağlantıları üzerinden hangi komutların çalıştırılabileceğini kontrol eder. Şu adresten indirilebilir:

http://raf.org/sshdo/ (buradaki kılavuz sayfalarını okuyun) https://github.com/raforg/sshdo/

Denenen tüm komutlara izin vermek için bir eğitim moduna ve öğrenilen komutlara kalıcı olarak izin vermek için gereken yapılandırmayı üretmek için bir --learn seçeneğine sahiptir. Daha sonra eğitim modu kapatılabilir ve diğer komutlar uygulanmayacaktır.

Ayrıca, gereksinimler zamanla değiştikçe en az ayrıcalığı korumak için artık kullanılmayan komutlara izin vermeyi durduran bir --unlearn seçeneğine de sahiptir.

Neye izin verdiği konusunda çok titiz. Herhangi bir argüman içeren bir komuta izin vermez. Yalnızca tam kabuk komutlarına izin verilebilir.

Ancak, yalnızca komut satırında görünen rakamlarda değişen benzer komutları temsil etmek için basit kalıpları destekler (örn. Sıra numaraları veya tarih / saat damgaları).

Bu, ssh komutları için bir güvenlik duvarı veya beyaz liste kontrolü gibidir.

Ve farklı kullanıcılar için izin verilen farklı komutları destekler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.