나는 (이유 때문에) C로 HTTP 서버 데몬을 작성하고 이를 관리하기 위해 systemd 단위 파일을 사용하고 있습니다.
저는 20년 전인 1995년쯤에 디자인한 애플리케이션을 다시 작성하고 있습니다. 그들이 사용하는 시스템은 먼저 chroot, 그 다음 setuid 및 표준 절차입니다.
이전 직장에서는 어떤 프로세스도 루트로 실행하지 않는 것이 일반적인 정책이었습니다. 이에 대한 사용자/그룹을 생성하고 거기에서 실행합니다. 물론 시스템은 일부 작업을 루트로 실행하지만 루트 없이도 모든 비즈니스 로직 처리를 구현할 수 있습니다.
이제 HTTP 데몬의 경우 애플리케이션 내에서 chroot를 수행하지 않으면 루트 없이 실행할 수 있습니다. 그렇다면 응용 프로그램이 절대 루트로 실행되지 않는 것이 더 안전하지 않을까요?
처음부터 mydaemon-user로 실행하는 것이 더 안전하지 않을까요? 루트로 시작하고 chrooting한 다음 mydaemon-user로 setuid를 시작하는 대신에?
답변1
다른 사람들이 귀하의 요점을 이해하지 못하는 것 같습니다. 물론 이미 명확하게 알고 있는 변경된 루트를 사용하려는 이유도 아니며, 데몬을 제한하기 위해 무엇을 할 수 있는지도 아닙니다. 데몬 프로세스는 권한이 없는 사용자 계정의 도움으로 실행되지만 왜 이런 일을 하는가?애플리케이션 내부. 실제로 그 이유에 대한 꽤 좋은 예가 있습니다.
httpd
Daniel 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
, 로드되는 공유 라이브러리, 프로그램 초기화 중에 /etc
프로그램 /run
로더 /dev
나 C 런타임 라이브러리에서 액세스하는 특수 파일이 나타납니다( C 또는 C++ truss
로 프로그래밍하는 경우). strace
, 당신은 매우 놀랄 수도 있습니다),반품변경의 루트에 존재해야 합니다. 그렇지 않으면 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
, 등. )
추가 읽기
- 번스타인, 다니엘(1996).
httpd
.공개 문서. cr.yp.to. httpd
.소프트웨어 통합(Daniel J. Bernstein). 소프트웨어. 조나단 드 보인 폴라드. 2016.gopherd
.소프트웨어 통합(Daniel J. Bernstein). 소프트웨어. 조나단 드 보인 폴라드. 2017.- https://unix.stackexchange.com/a/353698/5132
- https://github.com/janmojzis/httpfile/blob/master/droproot.c
답변2
avahi-daemon
귀하의 질문에 대한 많은 세부 사항이 제가 최근에 본 내용 에도 동일하게 적용된다고 생각합니다 . (다른 세부 사항을 놓쳤을 수도 있습니다.) chroot에서 avahi-daemon을 실행하면 avahi-daemon이 손상된 경우 많은 이점이 있습니다. 여기에는 다음이 포함됩니다.
- 사용자의 홈 디렉토리를 읽을 수 없으며 개인 정보를 훔칠 수 없습니다.
- /tmp에 기록하여 다른 프로그램의 버그를 이용할 수 없습니다. 그러한 오류에는 적어도 전체 클래스가 있습니다. 예를 들어https://www.google.co.uk/search?q=tmp+race+security+bug
- chroot 외부에서는 Unix 소켓 파일을 열 수 없으며 다른 데몬이 파일의 메시지를 듣고 읽을 수 있습니다.
때를아니요dbus 또는 이와 유사한 것을 사용하십시오. avahi-daemon은 dbus를 사용하므로 chroot 내부에서도 시스템 dbus에 대한 액세스를 보장합니다. 시스템의 dbus에서 메시지를 보내는 기능이 필요하지 않은 경우 해당 기능을 거부하는 것은 매우 좋은 보안 기능이 될 수 있습니다.
시스템 단위 파일을 사용하여 관리
avahi-daemon을 재정의하는 경우 보안을 위해 systemd에 의존하도록 선택할 수 있으며 예를 들어 ProtectHome
avahi-daemon을 변경하여 이러한 보호 기능을 추가 계층으로 추가하고 chroot가 보장할 수 없는 몇 가지 추가 보호 기능을 추가하는 것이 좋습니다. . 여기에서 제가 생각해낸 옵션의 전체 목록을 볼 수 있습니다.
https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a
avahi-daemon이 이렇게 하면 더 많은 제한을 사용할 수 있을 것 같습니다.아니요chroot 자체를 사용하십시오. 그 중 일부는 커밋 메시지에 언급되어 있습니다. 이것이 어느 정도까지 적용되는지 잘 모르겠습니다.
내가 사용하고 있는 보호 기능은 데몬이 Unix 소켓 파일을 여는 것을 제한하지 않습니다(위의 3번 항목).
또 다른 방법은 SELinux를 사용하는 것입니다. 그러나 애플리케이션을 Linux 배포판의 하위 집합과 연결할 수 있습니다. 여기서 SELinux를 긍정적으로 보는 이유는 SELinux가 dbus에 대한 프로세스의 액세스를 세밀한 방식으로 제한하기 때문입니다. 예를 들어, 일반적 systemd
으로 메시지를 보낼 수 있어야 하는 버스 이름 목록에 이 이름이 없을 것으로 예상할 것입니다 . :-).
"systemd sandbox를 사용하는 것이 chroot/setuid/umask/...보다 안전한지 알고 싶습니다."
요약: 왜 둘 다 될 수 없나요? 위의 내용을 조금 해석해 보겠습니다. :-).
포인트 3을 고려하면 chroot를 사용하면 더 많은 제한이 제공됩니다. ProtectHome=과 친구들은 chroot처럼 제한하려고 시도하지도 않습니다. (예를 들어 systemd 옵션 블랙리스트를 지정하지 않으면 /run
일반적으로 유닉스 소켓 파일을 블랙리스트에 추가합니다).
chroot는 파일 시스템 액세스를 제한하는 것이 매우 강력할 수 있음을 보여 주지만 그렇지 않습니다.모든 것Linux에서는 파일입니다 :-). 파일 이외의 콘텐츠를 제한할 수 있는 몇 가지 시스템 옵션이 있습니다. 이는 프로그램이 손상된 경우 유용하며, 취약점을 악용하려고 시도할 수 있는 사용 가능한 커널 기능을 줄일 수 있습니다. 예를 들어, avahi-daemon에는 블루투스 소켓이 필요하지 않으며 귀하의 웹 서버에도 필요하지 않은 것 같습니다 :-). 따라서 AF_BLUETOOTH 주소 계열에 대한 액세스 권한을 부여하지 마십시오. AF_INET, AF_INET6 또는 심지어 AF_UNIX 를 화이트리스트에 추가하려면 이 옵션을 사용하세요 RestrictAddressFamilies=
.
사용하는 각 옵션에 대한 설명서를 읽어보세요. 일부 옵션은 다른 옵션과 결합할 때 더 효율적이며, 일부 옵션은 모든 CPU 아키텍처에서 사용할 수 없습니다. (CPU가 나빠서가 아니라, 그 CPU의 리눅스 포트가 충분히 설계되지 않았기 때문인 것 같습니다.)
(여기에는 일반적인 원칙이 있습니다. 거부하고 싶은 것보다 허용하고 싶은 것의 목록을 작성할 수 있다면 더 안전합니다. chroot를 정의하면 액세스할 수 있는 파일 목록이 제공되는 것과 마찬가지로 이 More 차단하고 싶다고 말하는 것보다 신뢰할 수 있습니다 /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가 관리할 항목은 동적 사용자에게 올바르게 할당되어 있음에 유의하세요.