AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 447305
Accepted
mur
mur
Asked: 2018-06-02 04:29:02 +0800 CST2018-06-02 04:29:02 +0800 CST 2018-06-02 04:29:02 +0800 CST

Por que eu faria chroot para sandboxing por segurança se meu aplicativo pode ser executado desde o início em um nível inferior?

  • 772

Estou escrevendo um daemon de servidor HTTP em C (existem razões para isso), gerenciando-o com o arquivo de unidade systemd.

Estou reescrevendo um aplicativo projetado há 20 anos, por volta de 1995. E o sistema que eles usam é chroot e depois setuid, e o procedimento padrão.

Agora, em meu trabalho anterior, a política usual era que você nunca executasse nenhum processo como root. Você cria um usuário/grupo para ele e executa a partir daí. É claro que o sistema executou algumas coisas como root, mas poderíamos realizar todo o processamento da lógica de negócios sem ser root.

Agora, para o daemon HTTP, posso executá-lo sem root se não fizer chroot dentro do aplicativo. Portanto, não é mais seguro para o aplicativo nunca ser executado como root?

Não é mais seguro executá-lo como mydaemon-user desde o início? Em vez de iniciá-lo com root, chrooting e setuid para mydaemon-user?

chroot daemon
  • 3 3 respostas
  • 2076 Views

3 respostas

  • Voted
  1. Best Answer
    JdeBP
    2018-06-02T06:14:54+08:002018-06-02T06:14:54+08:00

    Parece que outros não entenderam o seu ponto, o que não foi motivo para usar raízes alteradas, o que é claro que você já sabe, nem o que mais você pode fazer para impor limites aos daemons, quando você também sabe claramente sobre correr sob a égide de contas de usuário sem privilégios; mas por que fazer essas coisas dentro do aplicativo . Na verdade, há um exemplo bastante preciso do porquê.

    Considere o projeto do httpdprograma daemon no pacote publicfile de Daniel J. Bernstein. A primeira coisa que ele faz é alterar root para o diretório raiz que foi instruído a usar com um argumento de comando e, em seguida, descartar privilégios para o ID do usuário não privilegiado e o ID do grupo que são passados ​​em duas variáveis ​​de ambiente.

    Os conjuntos de ferramentas de gerenciamento de daemon têm ferramentas dedicadas para coisas como alterar o diretório raiz e acessar IDs de usuários e grupos sem privilégios. O runit de Gerrit Pape tem chpst. Meu conjunto de ferramentas nosh tem chroote setuidgid-fromenv. O s6 de Laurent Bercot tem s6-chroote s6-setuidgid. Perp de Wayne Marshall tem runtoole runuid. E assim por diante. De fato, todos eles têm o próprio conjunto de ferramentas daemontools de M. Bernstein setuidgidcomo antecedente.

    Alguém poderia pensar que é possível extrair a funcionalidade httpde usar essas ferramentas dedicadas. Então, como você imagina, nenhuma parte do programa do servidor é executada com privilégios de superusuário.

    O problema é que, como consequência direta, é necessário muito mais trabalho para configurar a raiz alterada, e isso expõe novos problemas.

    Com o Bernstein httpdcomo está, os únicos arquivos e diretórios que estão na árvore do diretório raiz são aqueles que serão publicados para o mundo. Não há mais nada na árvore. Além disso, não há razão para que qualquer arquivo de imagem de programa executável exista nessa árvore.

    Mas mova o diretório raiz para um programa de carregamento em cadeia (ou systemd) e, de repente, o arquivo de imagem do programa para httpd, quaisquer bibliotecas compartilhadas que ele carregue e quaisquer arquivos especiais em /etc, /run, e /devque o carregador de programa ou a biblioteca de tempo de execução C acesse durante a inicialização do programa (o que você pode achar bastante surpreendente se você truss/ straceum programa C ou C++), também deve estar presente na raiz alterada. Caso contrário httpd, não pode ser acorrentado e não será carregado/executado.

    Lembre-se de que este é um servidor de conteúdo HTTP(S). Ele pode servir potencialmente qualquer arquivo (legível por todo o mundo) na raiz alterada. Isso agora inclui coisas como suas bibliotecas compartilhadas, seu carregador de programa e cópias de vários arquivos de configuração de carregador/CRTL para seu sistema operacional. E se por algum meio (acidental) o servidor de conteúdo tiver acesso para gravar coisas, um servidor comprometido pode possivelmente obter acesso de gravação à imagem do programa para httpdsi mesmo ou até mesmo ao carregador de programas do seu sistema. (Lembre-se de que agora você tem dois conjuntos paralelos de diretórios /usr, /lib, /etc, /rune /devpara mantê-los seguros.)

    Nada disso é o caso em que httpdaltera o root e descarta os próprios privilégios.

    Então você negociou com uma pequena quantidade de código privilegiado, que é bastante fácil de auditar e que roda logo no início do httpdprograma, rodando com privilégios de superusuário; por ter uma superfície de ataque bastante expandida de arquivos e diretórios dentro da raiz alterada.

    É por isso que não é tão simples como fazer tudo externamente ao programa de serviço.

    Observe que isso é, no entanto, um mínimo de funcionalidade em httpdsi. Todo o código que faz coisas como procurar no banco de dados de contas do sistema operacional o ID do usuário e o ID do grupo para colocar nessas variáveis ​​de ambiente é externo ao httpdprograma, em comandos auditáveis ​​autônomos simples, como envuidgid. (E, claro, é uma ferramenta UCSPI, portanto, não contém nenhum código para escutar na(s) porta(s) TCP relevante(s) ou para aceitar conexões, sendo essas o domínio de comandos como tcpserver, tcp-socket-listen, tcp-socket-accept, s6-tcpserver4-socketbinder, s6-tcpserver4de assim por diante.)

    Leitura adicional

    • Daniel J. Bernstein (1996). httpd. publicfile . cr.yp.to.
    • httpd. Todos os softwares de Daniel J. Bernstein em um . Programas. Jonathan de Boyne Pollard. 2016.
    • gopherd. Todos os softwares de Daniel J. Bernstein em um . Programas. Jonathan de Boyne Pollard. 2017.
    • https://unix.stackexchange.com/a/353698/5132
    • https://github.com/janmojzis/httpfile/blob/master/droproot.c
    • 29
  2. sourcejedi
    2018-06-02T04:56:48+08:002018-06-02T04:56:48+08:00

    Acho que muitos detalhes da sua pergunta podem se aplicar igualmente a avahi-daemon, que examinei recentemente. (Posso ter perdido outro detalhe que difere). A execução do avahi-daemon em um chroot tem muitas vantagens, caso o avahi-daemon seja comprometido. Esses incluem:

    1. ele não pode ler o diretório inicial de nenhum usuário e exfiltrar informações privadas.
    2. ele não pode explorar bugs em outros programas gravando em /tmp. Existe pelo menos uma categoria inteira de tais bugs. Por exemplo, https://www.google.co.uk/search?q=tmp+race+security+bug
    3. ele não pode abrir nenhum arquivo de soquete unix que esteja fora do chroot, no qual outros daemons podem estar ouvindo e lendo mensagens.

    O ponto 3 pode ser particularmente bom quando você não está usando dbus ou similar... Acho que o avahi-daemon usa dbus, então ele garante o acesso ao dbus do sistema mesmo de dentro do chroot. Se você não precisa da capacidade de enviar mensagens no dbus do sistema, negar essa capacidade pode ser um bom recurso de segurança.

    gerenciando-o com o arquivo de unidade systemd

    Observe que, se o avahi-daemon for reescrito, ele poderá optar por confiar no systemd para segurança e usar, por exemplo, ProtectHome. Propus uma alteração no avahi-daemon para adicionar essas proteções como uma camada extra, juntamente com algumas proteções adicionais que não são garantidas pelo chroot. Você pode ver a lista completa de opções que propus aqui:

    https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a

    Parece que há mais restrições que eu poderia ter usado se o avahi-daemon não usasse o próprio chroot, algumas das quais são mencionadas na mensagem de confirmação. Não tenho certeza de quanto isso se aplica.

    Observe que as proteções que usei não teriam limitado o daemon de abrir arquivos de soquete unix (ponto 3 acima).

    Outra abordagem seria usar o SELinux. No entanto, você estaria vinculando seu aplicativo a esse subconjunto de distribuições do Linux. A razão pela qual pensei no SELinux positivamente aqui é que o SELinux restringe o acesso que os processos têm no dbus, de maneira refinada. Por exemplo, acho que você pode esperar que systemdisso não esteja na lista de nomes de ônibus para os quais você precisa enviar mensagens :-).

    "Eu queria saber se usar sandbox systemd é mais seguro do que chroot/setuid/umask/..."

    Resumo: por que não os dois? Vamos decodificar um pouco o que foi dito acima :-).

    Se você pensar no ponto 3, usar o chroot fornece mais confinamento. ProtectHome= e seus amigos nem tentam ser tão restritivos quanto o chroot. (Por exemplo, nenhuma das listas negras de opções do systemd nomeadas /run, onde tendemos a colocar arquivos de soquete unix).

    chroot mostra que restringir o acesso ao sistema de arquivos pode ser muito poderoso, mas nem tudo no Linux é um arquivo :-). Existem opções do systemd que podem restringir outras coisas, que não são arquivos. Isso é útil se o programa estiver comprometido, você pode reduzir os recursos do kernel disponíveis para ele, o que pode tentar explorar uma vulnerabilidade. Por exemplo, o avahi-daemon não precisa de soquetes bluetooth e acho que seu servidor web também não :-). Portanto, não dê acesso à família de endereços AF_BLUETOOTH. Apenas coloque AF_INET, AF_INET6 e talvez AF_UNIX na lista de permissões, usando a RestrictAddressFamilies=opção.

    Por favor, leia os documentos para cada opção que você usa. Algumas opções são mais eficazes em combinação com outras e algumas não estão disponíveis em todas as arquiteturas de CPU. (Não porque a CPU seja ruim, mas porque a porta do Linux para essa CPU não foi tão bem projetada. Eu acho).

    (Existe um princípio geral aqui. É mais seguro se você puder escrever listas do que deseja permitir, não do que deseja negar. Como definir um chroot, fornece uma lista de arquivos que você pode acessar, e isso é mais robusto do que dizer que deseja bloquear /home).

    Em princípio, você mesmo pode aplicar todas as mesmas restrições antes de setuid(). É tudo apenas código que você pode copiar do systemd. No entanto, as opções de unidade do systemd devem ser significativamente mais fáceis de escrever e, como estão em um formato padrão, devem ser mais fáceis de ler e revisar.

    Portanto, recomendo apenas a leitura da seção de sandbox man systemd.execem sua plataforma de destino. Mas se você deseja o design mais seguro possível, não teria medo de tentar chroot(e depois descartar rootprivilégios) em seu programa também . Há uma compensação aqui. O uso chrootimpõe algumas restrições em seu design geral. Se você já tem um design que usa chroot e parece fazer o que você precisa, isso parece ótimo.

    • 7
  3. Lucas Werkmeister
    2018-06-02T05:33:43+08:002018-06-02T05:33:43+08:00

    Se você pode confiar no systemd, então é realmente mais seguro (e mais simples!) deixar o sandbox para o systemd. (Claro, o aplicativo também pode detectar se foi iniciado em sandbox pelo systemd ou não, e o próprio sandbox se ainda for root.) O equivalente ao serviço que você descreve seria:

    [Service]
    ExecStart=/usr/local/bin/mydaemon
    User=mydaemon-user
    RootDirectory=...
    

    Mas não precisamos parar por aí. O systemd também pode fazer muitos outros tipos de sandbox para você – aqui estão alguns exemplos:

    [Service]
    # allocate separate /tmp and /var/tmp for the service
    PrivateTmp=yes
    # mount / (except for some subdirectories) read-only
    ProtectSystem=strict
    # empty /home, /root
    ProtectHome=yes
    # disable setuid and other privilege escalation mechanisms
    NoNewPrivileges=yes
    # separate network namespace with only loopback device
    PrivateNetwork=yes
    # only unix domain sockets (no inet, inet6, netlink, …)
    RestrictAddressFamilies=AF_UNIX
    

    Consulte man 5 systemd.execpara muito mais diretivas e descrições mais detalhadas. Se você tornar seu daemon soquete ativável ( man 5 systemd.socket), você pode até usar as opções relacionadas à rede: o único link do serviço para o mundo externo será o soquete de rede que recebeu do systemd, ele não poderá se conectar a mais nada. Se for um servidor simples que escuta apenas em algumas portas e não precisa se conectar a outros servidores, isso pode ser útil. (As opções relacionadas ao sistema de arquivos também podem torná-lo RootDirectoryobsoleto, na minha opinião, então talvez você não precise mais se preocupar em configurar um novo diretório raiz com todos os binários e bibliotecas necessários.)

    As versões mais recentes do systemd (desde v232) também suportam DynamicUser=yes, onde o systemd alocará automaticamente o usuário do serviço para você apenas durante o tempo de execução do serviço. Isso significa que você não precisa registrar um usuário permanente para o serviço e funciona bem, desde que o serviço não grave em nenhum local do sistema de arquivos diferente de StateDirectory, LogsDirectorye CacheDirectory(que você também pode declarar no arquivo de unidade – veja man 5 systemd.exec, novamente – e qual systemd irá gerenciar, tomando cuidado para atribuí-los corretamente ao usuário dinâmico).

    • 1

relate perguntas

  • Pode pingar 8.8.8.8, mas sem acesso à internet - Manjaro linux

  • chroot um usuário para mais de um diretório em locais diferentes

  • Systemctl remove unidade da lista de falhas

  • Como adicionar localidades a um sistema chroot programaticamente?

  • A pasta da biblioteca Steam deve estar no sistema de arquivos executável

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve