루트 권한을 가진 파일에 프로그래밍 방식으로 쓰는 가장 안전한 방법은 무엇입니까?


35

특정 시간에 대규모 응용 프로그램은 루트 권한이 필요한 파일에 적은 수의 쓰기 작업을 수행해야합니다. 실제로 파일이 아니라 Linux에 파일로 노출되는 하드웨어 인터페이스입니다.

전체 응용 프로그램에 루트 권한을 부여하지 않기 위해 중요한 작업을 수행하는 bash 스크립트를 작성했습니다. 예를 들어 다음 스크립트는 하드웨어 인터페이스의 포트 17을 출력으로 활성화합니다.

echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction

그러나 suid내 시스템에서 bash 스크립트에 대해 비활성화 되어 있으므로 이것을 달성하는 가장 좋은 방법이 무엇인지 궁금합니다.

  1. 여기에 제시된 해결 방법을 사용 하십시오.

  2. 스크립트를 sudo호출 할 때 비밀번호가 필요하지 않도록 기본 애플리케이션에서 스크립트를 호출하고 sudoers 목록을 편집하십시오. 에 sudo 권한을 부여하는 것이 약간 불편합니다 echo.

  3. 로 C 프로그램을 작성하고 fprintfsuid root로 설정하십시오. 문자열과 파일 이름을 하드 코딩하고 루트 만 편집 할 수 있는지 확인하십시오. 또는 텍스트 파일에서 문자열을 읽고 아무도 파일을 편집 할 수 없도록합니다.

  4. 나에게 발생하지 않았으며 위에서 제시 한 것보다 안전하거나 간단한 다른 솔루션?


10
루트 권한으로 프로그램을 시작하고 파일을 열고 권한을 삭제하지 않는 이유는 무엇입니까? 그것이 모든 웹 서버 등이 소켓을 위해하는 방법입니다. 효과적으로, 당신은 루트로 실행되고 있지 않으며 그렇게하는 도우미가 필요하지 않습니다.
Damon

답변:


33

sudo액세스 권한을 부여 할 필요가 없습니다 echo. 실제로, 예를 들어로 sudo echo foo > bar리디렉션이 루트가 아닌 원래 사용자로 수행되므로 의미가 없습니다.

함께 작은 스크립트를 호출 sudoNOPASSWD:에 대한 액세스를 해당 스크립트 (및 다른 유사한 스크립트) 사용자가 그것을 액세스해야 (들).

이것은 항상 가장 안전하고 안전한 방법 sudo입니다. 루트 권한이 필요한 적은 수의 명령을 별도의 스크립트로 분리하고 신뢰할 수 없거나 부분적으로 신뢰할 수없는 사용자는 해당 스크립트를 루트로만 실행할 수 있습니다.

작은 sudo스크립트는 사용자로부터 인수 (또는 입력)를 취하지 말아야합니다 (즉, 호출하는 다른 프로그램은 하드 코딩 된 옵션과 인수를 가져야합니다). 사용자로부터 동의합니다.

검증에서 편집증을 가지십시오-제외 할 '알려진 나쁜 것'을 찾거나 '알려진 좋은 것'만 허용하고 불일치 나 오류 또는 원격으로 의심되는 것을 중단하십시오.

검증 가능한 스크립트 (가 않습니다 바람직 전에 일찍 발생한다 어떤 루트로 다른 사람을).


나는 정말 내가 처음이 답을 쓸 때이 문제를 언급 할 뻔했지만 스크립트가 쉘 스크립트 인 경우는 반드시 제대로 인용 모든 변수를. 어떤 식 으로든 사용자가 제공 한 입력을 포함하는 변수를 인용 할 때는 특히주의해야 하지만 일부 변수가 안전하다고 가정하지 마십시오 . QUOTE THEM ALL .

즉, 잠재적으로 (예를 들면 사용자가 제어 환경 변수를 포함한다 "$PATH", "$HOME", "$USER"등을 명확히 포함 "$QUERY_STRING"하고 "HTTP_USER_AGENT"등등 CGI 스크립트하여). 사실, 그것들을 모두 인용하십시오. 인수가 여러 개인 명령 행을 구성해야하는 경우 배열을 사용하여 인수 목록을 작성하고-를 인용하십시오 "${myarray[@]}".

내가 아직 충분히 "그들 모두를 인용"한다고 말했습니까? 기억해. 해.


18
스크립트 자체는 root 가 소유하고 권한 500이 있어야 함을 언급하지 않았습니다.
Wildcard

13
최소한 쓰기 권한을 제거하십시오. 정말 내 요점이었다. 나머지는 딱딱 해지고 있습니다.
와일드 카드

10
신중하게 작성된 C 프로그램은 쉘 스크립트보다 공격 표면이 더 작습니다.
user253751

7
아마도 @immibis. 그러나 쉘 스크립트보다 작성하고 디버깅하는 데 시간이 오래 걸립니다. 또한 C 컴파일러 (일부 프로덕션 서버에서는 공격자가 악용을 컴파일하기 어렵게하여 보안 위험을 줄이기 위해 금지)가 있어야합니다. 또한 초보자가 중간 수준의 sysadmin 또는 프로그래머에게 작성한 셸 스크립트 IMO는 비슷한 기술을 가진 사람이 작성한 C 프로그램보다 악용 될 가능성이 적습니다 (특히 사용자 제공 데이터를 수락하고 유효성을 검사해야하는 경우).
cas

3
@JonasWielicki-우리는 지금 사실이 아니라 의견의 영역에 잘 속해 있다고 생각합니다. 쉘 또는 C (또는 perl 또는 python 또는 awk 등)에 대해 공격 가능한 실수가 발생하기 쉬운 유효한 인수를 만들 수 있습니다. 실제로, 그것은 주로 프로그래머의 기술과 세부 사항에 대한 관심 (그리고 피곤함, 서두름,주의 등)에 달려 있습니다. 사실, 더 낮은 수준의 언어는 더 높은 수준의 언어에서 훨씬 적은 코드 행으로 수행 할 수있는 작업을 수행하기 위해 더 많은 코드를 작성해야하는 경향이 있습니다. 각 LoC는 실수 할 것.
cas

16

gpio 파일에서 소유자를 확인하십시오.

ls -l /sys/class/gpio/

대부분 그룹이 소유하고 있음을 알게 될 것입니다 gpio.

-rwxrwx--- 1 root     gpio     4096 Mar  8 10:50 export
...

이 경우 gpiosudo없이 액세스 권한을 부여 하기 위해 사용자를 그룹에 간단히 추가 할 수 있습니다 .

sudo usermod -aG gpio myusername

변경 사항을 적용하려면 로그 아웃 한 후 다시 로그인해야합니다.


작동하지 않습니다. 실제로, 모든 것의 그룹 소유자 /sys/class/gpio/는 gpio이지만, 그 그룹에 자신을 추가 한 후에도 거기에 아무것도 쓰려고 할 때마다 여전히 "permission denied"가 발생합니다.
vsz

1
문제는 파일 /sys/class/gpio/이 실제로 /sys/devices/platform/soc/<some temporary name>/gpio소유자와 그룹이 루트 인 심볼릭 링크라는 것 입니다.
vsz

4
@vsz 시도 했습니까 chgrp gpio /sys/devices/platform/soc/*/gpio? 아마도 그런 파일이 시작 파일에있을 수 있습니다.
jpa

예,하지만 그렇게 간단하지 않습니다. 그들은 항상 다른 방법으로 생성되기 때문에, 내가 좋아하는 뭔가를 사용했다chgrp gpio `readlink -f /sys/class/gpio/gpio18`/*
VSZ

7

이를위한 한 가지 솔루션 (특히 Linux 데스크톱에서 사용되지만 다른 경우에도 적용 가능)은 D-Bus 를 사용 하여 권한 부여를 위해 루트 및 폴킷 으로 실행되는 소규모 서비스를 활성화하는 것 입니다. 이것은 기본적으로 폴킷을 위해 설계된 것 입니다. 입문서 에서 :

polkit은 권한이없는 프로그램 ( "CLIENTS")에 서비스를 제공하는 권한있는 프로그램 ( "MECHANISMS")이 사용할 수 있도록 인증 API를 제공합니다. 시스템 아키텍처 및 큰 그림은 polkit 매뉴얼 페이지를 참조하십시오.

권한이없는 큰 프로그램은 도우미 프로그램을 실행하는 대신 버스에서 요청을 보냅니다. 도우미는 시스템 부팅시 시작된 데몬으로 실행되거나 systemd에서 필요에 따라 활성화 될 수 있습니다 . 그런 다음 도우미는 polkit을 사용하여 요청이 승인 된 장소에서 오는지 확인합니다. (이 경우 과도한 것으로 느껴지면 다른 하드 코딩 된 인증 / 권한 부여 메커니즘을 사용할 수 있습니다.)

나는 D-Bus를 통한 통신에 대한 좋은 기본 기사를 찾았 으며 테스트하지는 않았지만 이것은 믹스에 polkit을 추가하는 기본 예제 인 것으로 보입니다 .

이 방법에서는 setuid로 표시 할 필요가 없습니다.


5

이를 수행하는 한 가지 방법은 C로 작성된 setuid-root 프로그램을 만들어 필요한 것만 수행하는 것입니다. 귀하의 경우에는 사용자 입력을 전혀 볼 필요가 없습니다.

#include <unistd.h>
#include <string.h>
#include <stdio.h>  // for perror(3)
// #include ...  more stuff for open(2)

static void write_str_to_file(const char*fn, const char*str) {
    int fd = open(fn, O_WRONLY)
    if (-1 == fd) {
        perror("opening device file");  // make this a CPP macro instead of function so you can use string concat to get the filename into the error msg
        exit(1);
    }
    int err = write(fd, str, strlen(str));
    // ... error check
    err = close(fd);
    // ... error check
}

int main(int argc, char**argv) {
    write_string_to_file("/sys/class/gpio/export", "17");
    write_string_to_file("/sys/class/gpio/gpio17/direction", "out");
    return 0;
}

환경 변수 등을 통해 이것을 바꿀 수있는 방법은 없습니다. 왜냐하면 모두 시스템 호출을 수행하기 때문입니다.

단점 : 모든 시스템 호출의 반환 값을 확인해야합니다.

거꾸로 : 오류 검사가 정말 쉽습니다. 오류가 전혀 없다면 그냥 perror구제하십시오 : 0이 아닌 상태로 종료하십시오. 오류가 있으면으로 조사하십시오 strace. 정말 멋진 오류 메시지를 제공하기 위해이 프로그램 자체가 필요하지 않습니다.


2
나는 두 번째 파일이없는 것을 막기 위해 무엇이든 쓰기 전에 두 파일을 모두 열어보고 싶을지도 모른다. 그리고이 프로그램을 통해 실행할 sudo수 있으므로 setuid가 필요하지 않습니다. 또한, <fcntl.h>입니다 open().
Jonathan Leffler

3

sudo를위한 echo 대신 echo tee는 루트 파마를 제한해야하는 상황에 접근하는 일반적인 방법 중 하나입니다. / dev / null 로의 리디렉션은 출력 유출을 막는 것입니다. 티는 원하는 것을합니다.

echo "17" | sudo tee /sys/class/gpio/export > /dev/null
echo "out" | sudo tee /sys/class/gpio/gpio17/direction > /dev/null

5
tee로 실행할 수 있으면 sudo모든 파일을 덮어 쓰거나 추가 할 수 있습니다 (예 /etc/passwd: 새 uid = 0 계정 추가 만 포함 ). 또한 모든 명령이 실행되도록 허용 할 수도 있습니다 sudo(BTW /etc/sudoers는 '모든 파일'에 속해 있으므로 덮어 쓸 수 있음 sudo tee)
cas

2
분명히, 당신은 별도의 질문에 대한 이 답변tee설명 된 것처럼 쓸 수 있는 파일을 제한 할 수 있습니다 . 일부 사람들은 사용 된 원래 구문에 문제가 있고 해당 문제에 대한 수정 사항을 제안하므로 주석도 읽으십시오.
Alex

1
@alex, 예, sudo의 모든 명령으로이를 수행 할 수 있습니다-허용되는 인수를 제한하십시오. 을 사용 tee하여 많은 파일에서 작업 을 허용 하거나 수행 하려는 경우 구성이 매우 길고 복잡해질 수 있습니다 sudo.
cas

0

원하는 작업을 수행하는 스크립트를 만들 수 있습니다. 그런 다음 OpenSSH에서 사용하는 키를 제공하여 로그인 만 가능한 새 사용자 계정을 작성하십시오.

참고 : 키 파일이 있으면 누구나 해당 스크립트를 실행할 수 있으므로 작업을 수행하지 못하게하려는 사람이 OpenSSH 키 파일을 읽을 수 없는지 확인하십시오.

authorized_keys 파일의 OpenSSH 구성에서 키를 지정하기 전에 다음 "예제"텍스트에 설명 된대로 공백 (공백)으로 명령을 지정하십시오.

command="myscript" keydata optionalComment

이 구성 옵션은 OpenSSH 키가 특정 명령 만 실행하도록 제한 할 수 있습니다. 이제 권한을 부여하는 sudo가 있지만 OpenSSH 구성은 실제로 사용자가 수행 할 수있는 작업을 제한 / 제한하는 데 사용되는 솔루션의 일부이므로 사용자가 다른 명령을 실행하지 않습니다. 이것은 "스도"구성 파일만큼 복잡하지 않기 때문에 OpenBSD를 사용하거나 OpenBSD의 새로운 "doas"( "do as")가 더 널리 사용되기 시작하면 (사용하는 운영 체제의 향후 버전에서) sudo 구성의 복잡성으로 인해 어려움을 겪을 필요는 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.