추가 읽기

추가 읽기

나는 C로 HTTP 서버 데몬을 작성하고 있으며(이유가 있음) 시스템 단위 파일로 관리하고 있습니다.

저는 20년 전인 1995년쯤에 설계된 응용 프로그램을 다시 작성하고 있습니다. 그리고 그들이 사용하는 시스템은 chroot와 setuid, 그리고 표준 절차입니다.

이전 작업에서 일반적인 정책은 어떤 프로세스도 루트로 실행하지 않는다는 것이었습니다. 이에 대한 사용자/그룹을 생성하고 거기에서 실행합니다. 물론 시스템은 일부 작업을 루트로 실행했지만 루트가 아니더라도 모든 비즈니스 로직 처리를 수행할 수 있었습니다.

이제 HTTP 데몬의 경우 애플리케이션 내에서 chroot를 수행하지 않으면 루트 없이 실행할 수 있습니다. 그렇다면 응용 프로그램이 절대로 루트로 실행되지 않는 것이 더 안전하지 않습니까?

처음부터 mydaemon-user로 실행하는 것이 더 안전하지 않나요? 루트로 시작하는 대신 chrooting한 다음 mydaemon-user로 setuid를 설정하시겠습니까?

답변1

다른 사람들이 당신의 요점을 놓친 것 같습니다. 이것은 물론 당신이 이미 분명히 알고 있는 변경된 뿌리를 사용해야 하는 이유가 아니었고, 악마의 후원 아래서 달리는 것에 대해서도 분명히 알고 있을 때 데몬에 제한을 두기 위해 무엇을 할 수 있는지에 대한 이유가 아니었습니다. 권한이 없는 사용자 계정; 그런데 왜 이런 일을 해야 하는가?애플리케이션 내부. 실제로 그 이유에 대한 상당히 정확한 예가 있습니다.

httpdDaniel J. Bernstein의 publicfile 패키지에 있는 데몬 프로그램 의 디자인을 고려해보세요 . 가장 먼저 수행하는 작업은 루트를 명령 인수와 함께 사용하도록 지시받은 루트 디렉터리로 변경한 다음 두 개의 환경 변수에 전달된 권한이 없는 사용자 ID 및 그룹 ID에 대한 권한을 삭제하는 것입니다.

데몬 관리 도구 세트에는 루트 디렉터리 변경, 권한 없는 사용자 및 그룹 ID 삭제 등을 위한 전용 도구가 있습니다. Gerrit Pape의 runit은 다음과 같습니다.chpst. 내 nosh 도구 세트에는chroot그리고setuidgid-fromenv. 로랑 베르코의 s6는s6-chroot그리고s6-setuidgid. 웨인 마샬의 Perp는runtool그리고runuid. 기타 등등. 실제로 그들은 모두 M. Bernstein의 자체 daemontools 도구 세트를 가지고 있습니다.setuidgid선행으로.

httpd그러한 전용 도구 에서 기능을 추출하여 사용할 수 있다고 생각할 수도 있습니다 . 그러면 당신이 상상하는 대로,아니요서버 프로그램의 일부는 슈퍼유저 권한으로 실행됩니다.

문제는 직접적인 결과로 변경된 루트를 설정하기 위해 훨씬 더 많은 작업을 수행해야 하며 이로 인해 새로운 문제가 노출된다는 것입니다.

번스타인의 httpd상태로는오직루트 디렉터리 트리에 있는 파일과 디렉터리는 전 세계에 게시되는 것입니다. 있다다른 건 없어전혀 나무에. 게다가 이유도 없고어느실행 가능한 프로그램 이미지 파일이 해당 트리에 존재하도록 합니다.

그러나 루트 디렉터리 변경 사항을 체인 로딩 프로그램(또는 systemd)으로 옮기고 갑자기 에 대한 프로그램 이미지 파일 httpd, 로드되는 공유 라이브러리, , , 프로그램 로더 또는 C 런타임 라이브러리가 액세스하는 특수 파일을 /etc이동 합니다 /run. 프로그램 초기화 중에(C 또는 C++ 프로그램을 사용 /dev하는 경우 이는 매우 놀라운 일입니다 )trussstrace또한변경된 루트에 있어야 합니다. 그렇지 않으면 httpd연결할 수 없으며 로드/실행되지 않습니다.

이는 HTTP(S) 콘텐츠 서버라는 점을 기억하세요. 변경된 루트에 있는 모든 (누구나 읽을 수 있는) 파일을 잠재적으로 제공할 수 있습니다. 이제 여기에는 공유 라이브러리, 프로그램 로더, 운영 체제에 대한 다양한 로더/CRTL 구성 파일의 복사본 등이 포함됩니다. 그리고 (우연히) 콘텐츠 서버가 다음에 액세스할 수 있다는 뜻이라면쓰다문제가 발생하면 손상된 서버는 프로그램 이미지 httpd자체 또는 시스템의 프로그램 로더에 대한 쓰기 액세스 권한을 얻을 수 있습니다. (이제 보안을 유지하기 위해 /usr, /lib, /etc, /run및 디렉터리의 두 병렬 세트가 있다는 것을 기억하십시오.)/dev

httpd루트를 변경하고 권한 자체를 삭제하는 경우는 없습니다 .

따라서 당신은 감사하기가 매우 쉽고 프로그램 시작 시 바로 실행되며 httpd수퍼유저 권한으로 실행되는 소량의 권한 있는 코드를 가지고 거래했습니다. 변경된 루트 내에서 파일 및 디렉터리의 공격 표면이 크게 확장되었습니다.

이것이 서비스 프로그램 외부에서 모든 작업을 수행하는 것만큼 간단하지 않은 이유입니다.

그럼에도 불구하고 이는 그 자체 내에서 최소한의 기능임을 주목하세요 httpd. 먼저 운영 체제의 계정 데이터베이스에서 사용자 ID 및 그룹 ID를 검색하여 해당 환경 변수에 넣는 등의 작업을 수행하는 모든 코드~이다httpd와 같은 간단한 독립 실행형 감사 가능 명령을 사용하여 프로그램 외부에 있습니다 envuidgid. (물론 이는 UCSPI 도구이므로 관련 TCP 포트에서 수신 대기하거나 다음과 같은 명령 도메인인 연결을 수락하는 코드가 포함되어 있지 않습니다.tcpserver,tcp-socket-listen,tcp-socket-accept,s6-tcpserver4-socketbinder,s6-tcpserver4d, 등등.)

추가 읽기

답변2

avahi-daemon귀하의 질문에 대한 많은 세부 사항이 제가 최근에 살펴본 에도 동일하게 적용될 수 있다고 생각합니다 . (그러나 다른 세부 사항을 놓쳤을 수도 있습니다). chroot에서 avahi-daemon을 실행하면 avahi-daemon이 손상된 경우에 많은 이점이 있습니다. 여기에는 다음이 포함됩니다.

  1. 사용자 홈 디렉터리를 읽을 수 없으며 개인 정보를 유출할 수 없습니다.
  2. /tmp에 기록하여 다른 프로그램의 버그를 이용할 수 없습니다. 이러한 버그에는 적어도 하나의 전체 범주가 있습니다. 예:https://www.google.co.uk/search?q=tmp+race+security+bug
  3. 다른 데몬이 메시지를 듣고 읽을 수 있는 chroot 외부에 있는 Unix 소켓 파일을 열 수 없습니다.

포인트 3은 다음과 같은 경우에 특히 좋을 수 있습니다.~ 아니다dbus 또는 유사한 사용... avahi-daemon은 dbus를 사용하므로 chroot 내부에서도 시스템 dbus에 계속 액세스할 수 있도록 해줍니다. 시스템 dbus에서 메시지를 보내는 기능이 필요하지 않은 경우 해당 기능을 거부하는 것은 꽤 좋은 보안 기능일 수 있습니다.

systemd 단위 파일로 관리

avahi-daemon을 다시 작성한 경우 잠재적으로 보안을 위해 systemd에 의존하고 예를 들어 ProtectHome. 나는 chroot가 보장하지 않는 몇 가지 추가 보호 기능과 함께 이러한 보호 기능을 추가 계층으로 추가하기 위해 avahi-daemon에 대한 변경을 제안했습니다. 제가 제안한 옵션의 전체 목록은 여기에서 볼 수 있습니다:

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

avahi-daemon이 사용했다면 사용할 수 있었던 제한 사항이 더 많은 것 같습니다.~ 아니다chroot 자체를 사용하세요. 그 중 일부는 커밋 메시지에 언급되어 있습니다. 하지만 이것이 얼마나 적용될지는 잘 모르겠습니다.

내가 사용한 보호 조치는 데몬이 Unix 소켓 파일을 여는 것을 제한하지 않았습니다(위의 3번 항목).

또 다른 접근 방식은 SELinux를 사용하는 것입니다. 그러나 애플리케이션을 Linux 배포판의 하위 집합에 연결하게 될 것입니다. 여기서 SELinux를 긍정적으로 생각한 이유는 SELinux가 dbus에 대한 프로세스의 액세스를 세밀한 방식으로 제한하기 때문입니다. 예를 들어, systemd메시지를 보내는 데 필요한 버스 이름 목록에 이 이름이 없을 것으로 예상할 수 있을 것 같습니다 . :-).

"chroot/setuid/umask/보다 시스템 샌드박싱을 더 안전하게 사용하는지 궁금합니다..."

요약: 둘 다 안 되는 이유는 무엇입니까? 위의 내용을 조금 해석해 보겠습니다. :-).

포인트 3을 생각하면 chroot를 사용하면 더 많은 제한이 제공됩니다. ProtectHome=과 그 친구들은 chroot만큼 제한하려고 시도하지도 않습니다. (예를 들어, /run유닉스 소켓 파일을 저장하는 경향이 있는 systemd 옵션 blacklists 중 어느 것도 없습니다 .)

chroot는 파일 시스템 액세스를 제한하는 것이 매우 강력할 수 있음을 보여줍니다.모든 것Linux에서는 파일입니다 :-). 파일이 아닌 다른 사항을 제한할 수 있는 시스템 옵션이 있습니다. 이는 프로그램이 손상된 경우 유용합니다. 사용 가능한 커널 기능을 줄여 취약점을 악용하려고 시도할 수 있습니다. 예를 들어 avahi-daemon에는 블루투스 소켓이 필요하지 않으며 웹 서버도 필요하지 않은 것 같습니다. :-). 따라서 AF_BLUETOOTH 주소 계열에 대한 액세스 권한을 부여하지 마십시오. 옵션 을 사용하여 AF_INET, AF_INET6 및 AF_UNIX를 화이트리스트에 추가하세요 RestrictAddressFamilies=.

사용하는 각 옵션에 대한 문서를 읽어보세요. 일부 옵션은 다른 옵션과 함께 사용하면 더 효과적이며 일부는 모든 CPU 아키텍처에서 사용할 수 없습니다. (CPU가 나빠서가 아니라, 그 CPU의 리눅스 포트가 디자인이 좋지 않아서 그런 것 같습니다.)

(여기에는 일반적인 원칙이 있습니다. 거부하고 싶은 것이 아니라 허용하고 싶은 목록을 작성할 수 있다면 더 안전합니다. chroot를 정의하는 것과 마찬가지로 액세스가 허용된 파일 목록이 제공되며 이는 더욱 강력합니다. 차단하고 싶다고 말하는 것보다 /home).

원칙적으로 setuid() 이전에 동일한 제한 사항을 모두 적용할 수 있습니다. 그것은 모두 systemd에서 복사할 수 있는 코드일 뿐입니다. 그러나 systemd 단위 옵션은 작성하기가 훨씬 더 쉽고, 표준 형식이므로 읽고 검토하기도 더 쉽습니다.

man systemd.exec따라서 대상 플랫폼 의 샌드박싱 섹션을 읽어보는 것이 좋습니다 . 그러나 가능한 한 가장 안전한 설계를 원한다면 나는 귀하의 프로그램에서 시도하는 것을 두려워하지 않을 것입니다 chroot(그런 다음 권한을 삭제하는 것 ).root또한. 여기에는 절충안이 있습니다. 을 사용하면 chroot전체 디자인에 몇 가지 제약이 따릅니다. chroot를 사용하는 디자인이 이미 있고 필요한 작업을 수행하는 것 같다면 꽤 좋을 것 같습니다.

답변3

systemd를 사용할 수 있다면 샌드박싱을 systemd에 맡기는 것이 실제로 더 안전하고 간단합니다! (물론 응용 프로그램은 systemd에 의해 샌드박스로 실행되었는지 여부와 샌드박스 자체가 여전히 루트인지 여부도 감지할 수 있습니다.) 설명하는 서비스에 해당하는 것은 다음과 같습니다.

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

하지만 여기서 멈출 필요는 없습니다. systemd는 다른 많은 샌드박싱도 수행할 수 있습니다. 다음은 몇 가지 예입니다.

[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

man 5 systemd.exec더 많은 지시문과 자세한 설명을 보려면 를 참조하세요 . 데몬 소켓을 활성화 가능하게 만들면( man 5 systemd.socket) 네트워크 관련 옵션도 사용할 수 있습니다. 외부 세계에 대한 서비스의 유일한 링크는 systemd에서 수신한 네트워크 소켓이 되며 다른 어떤 것에도 연결할 수 없습니다. 일부 포트에서만 수신 대기하고 다른 서버에 연결할 필요가 없는 간단한 서버라면 이 방법이 유용할 수 있습니다. (제 생각에는 파일 시스템 관련 옵션도 RootDirectory쓸모없게 만들 수 있으므로 더 이상 필요한 모든 바이너리와 라이브러리가 포함된 새 루트 디렉터리를 설정할 필요가 없을 것입니다.)

최신 systemd 버전(v232 이후)도 지원합니다 DynamicUser=yes. 여기서 systemd는 서비스 런타임 동안에만 서비스 사용자를 자동으로 할당합니다. 즉, 서비스에 대한 영구 사용자를 등록할 필요가 없으며 서비스가 , 및 이외의 파일 시스템 위치에 쓰지 않는 한 잘 작동합니다 StateDirectory( LogsDirectory유닛 CacheDirectory파일에서 선언할 수도 있음). 를 다시 참조하세요 man 5 systemd.exec. 그러면 systemd가 이를 관리하고 동적 사용자에게 올바르게 할당하도록 주의를 기울일 것입니다.

관련 정보