![프로세스 교체 시 민감한 데이터](https://linux55.com/image/9896/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%20%EA%B5%90%EC%B2%B4%20%EC%8B%9C%20%EB%AF%BC%EA%B0%90%ED%95%9C%20%EB%8D%B0%EC%9D%B4%ED%84%B0.png)
내가 이렇게 한다고 가정해보자:
#!/bin/bash
content="foo"
pass="secret-password"
echo $content | ccrypt -f -k <(echo -n $pass)
프로세스 대체 파일에 설정된 권한을 신뢰하여 /dev/fd/*
해당 기간 동안 비밀번호를 안전하게 유지할 수 있습니까 ccrypt
?
답변1
분석해 보겠습니다.
content=$(cat -)
이는 와 동일합니다 content=$(cat)
. 사용되는 것명령 대체파이프를 사용 bash
합니다. 파이프의 한쪽 끝에는 cat
표준 입력에서 읽은 내용이 기록됩니다. bash
다른 쪽 끝은 그것을 읽고 $content
.
그러나 그렇게 하기 전에 후행 개행 문자를 제거하고 NUL 문자에 대한 차단도 제거합니다. 임의의 데이터를 변수에 저장할 수 있으려면 를 사용할 수 없으며 다음과 같은 작업을 bash
수행해야 합니다 .zsh
content=$(cat; echo .); content=${content%.}
개행 제거 문제를 해결합니다.
저장할 데이터는 $content
스크립트의 표준 입력을 통해 입력됩니다. 이것은 (Linux에서) 파이프로 복사되므로 에서도 /proc/pid-of-your-script/fd/0
사용할 수 있습니다 ./proc/pid-of-cat/fd/0
cat
bash
/proc/pid-of-cat/fd/1
/proc/pid-of-script/fd/fd-to-the-other-end-of-the-pipe
어쨌든 콘텐츠는 한 번만 사용하므로 $content
중간 단계를 수행할 필요가 없습니다.
pass=$1
여기서 당신은 비밀에 대해 이야기하고 있습니다열쇠스크립트의 첫 번째 매개변수에서 가져옵니다.
비밀 데이터를 명령줄 인수로 전달할 수 없습니다. 명령줄 매개변수는 비밀이 아닙니다. 의 출력에 나타납니다 ps -efwww
. Linux에서는 /proc/pid/cmdline
해당 파일이 포함된 파일을 누구나 읽을 수 있습니다. 기본적으로 Linux에서는 /proc/pid
관리상 동일한 euid를 가진 프로세스로 액세스를 제한할 수 있지만 동작이나 ps
기타 문제에 영향을 미치기 때문에 거의 수행되지 않습니다.
일부 시스템에서는 일부 프로세스 계정/감사 메커니즘을 통해 기록될 수도 있습니다.
echo $content
오류에는 여러 가지 이유가 있습니다.
echo
임의의 데이터와 함께 사용할 수 없습니다. 환경에 따라 , ...와-n
같은 인수 및 백슬래시와 같은 항목에서는 제대로 작동하지 않습니다 .-neneneene
- 따옴표가 없으면
$content
원하지 않는 분할+glob 연산자를 호출하는 것을 의미하며 와일드카드 문자를$content
포함 하면$IFS
문제가 발생할 수 있습니다 . - 추가 개행 문자를 추가합니다.
당신이 원하는 것:
printf %s "$content"
그리고 후행 개행 문자가 너무 일찍 제거되지 않도록 하세요.
파이프의 일부 이기 때문에 printf
하위 프로세스에서 실행되며 표준 출력은 파이프가 됩니다. Linux에서는 /proc/pid-of-that-child-process/fd/1
콘텐츠에 대한 액세스가 허용됩니다. 그럴 것이다 /proc/pid-of-ccript/0
.
존재하다
ccrypt -f -k <(echo -n $pass)
echo
과 인용되지 않은 질문이 다시 발생합니다 $pass
.
echo
(하위 프로세스에서 다시 실행) 파이프에 비밀번호를 씁니다. 파이프의 다른 쪽 끝은 fd에서 사용할 수 있습니다.N및 ccrypt
은 또는 과 같은 것으로 <(...)
확장됩니다 . 파일을 열고(새 fd에서) 해당 파일(Linux에서)을 다시 사용할 수 있습니다 ./dev/fd/n
/proc/self/fd/n
ccrypt
/proc/pid-of-ccrypt/fd/that-fd
/proc/pid-of-ccrypt/fd/n
/proc/pid-of-echo/fd/1
이제 코드의 주요 문제는 프로세스 대체나 다른 파이프가 아니라 암호가 명령(여기 스크립트)에 대한 명령줄 인수로 제공된다는 사실입니다.
프로세스 대체 에는 $(...)
명령 대체 및 |
. /dev/fd/x
그러나 동일한 euid(또는 루트)로 실행되는 다른 프로세스는 어쨌든 해당 프로세스의 메모리를 읽고(디버거가 수행하는 것처럼) 해당 비밀번호를 복구할 수 있습니다(또는 동일한 소스에서 비밀번호를 가져올 수도 있음).
Linux에는 기호 링크 와 동적 기호 링크 /dev/fd
가 있습니다 . 기본적으로 동일한 euid를 가진 프로세스는 읽을 수 있습니다(더 많은 제한 사항이 추가될 수 있지만 프로세스에 디버거를 연결할 수 있는 사람을 제한하는 것과 동일합니다)./proc/self/fd
/proc/self
/proc/the-pid
/proc/pid/fd
파이프를 가리키는 fd의 경우 /proc/pid/fd/that-fd
명명된 파이프처럼 작동합니다. 따라서 다른 프로세스(다시 동일한 euid 또는 루트로 실행)가 파이프의 내용을 훔칠 수 있습니다. 하지만 어쨌든 그렇게 할 수 있다면 프로세스 메모리의 내용을 직접 읽을 수도 있으므로 이를 방지하려고 노력할 필요가 없습니다.
명령줄에서 비밀번호를 전달하는 대신 환경 변수를 통해 비밀번호를 전달할 수 있습니다. 환경은 매개변수 목록보다 더 비공개적입니다. Linux에서는 /proc/pid/environ
동일한 euid(또는 euid )를 가진 root
프로세스에서만 읽을 수 있습니다.
따라서 스크립트는 다음과 같을 수 있습니다.
#! /bin/sh -
exec ccrypt -f -E PASSWORD
그리고 전화해
PASSWORD=secret-phrase the-script < data-to-encrypt