SSH를 통해 다른 서버와 통신해야 하는 데이터베이스 기반 애플리케이션이 있습니다. 웹 애플리케이션은 키 쌍을 생성하고 사용자에게 공개 키를 제공하거나 웹 양식 필드에서 암호화되지 않은 개인 키를 허용할 수 있습니다. 그런 다음 해독 가능한 암호화를 사용하여 키를 암호화하고 데이터베이스에 저장합니다.
웹 애플리케이션이 SSH 서버와 통신할 때 개인 키를 해독하고 어떻게든 이를 SSH에 제공해야 합니다. 안전한 임시 파일을 생성하고 mktemp
ssh를 통해 파일을 지정한 다음 파일을 삭제할 수 있지만 이는 추가 작업이며 새로운 방식으로 키를 노출하므로 필요하지 않은 것 같습니다. man ssh
, , 를 살펴봤는데 man ssh-agent
키 man ssh-add
를 먼저 파일에 추가하지 않고는 사용할 수 있는 방법이 없는 것 같습니다. 내가 무엇을 놓치고 있나요?
답변1
ssh
/etc와 같은 기존 도구를 사용하려면 ssh-agent
파일에 키를 제공해야 합니다.
또 다른, 아마도 더 실현 가능한 솔루션은 ssh
애플리케이션에서 직접 클라이언트를 구현하고 타사 라이브러리에 의존하는 것입니다.클립쉬또는 ssh
/를 확장하여 ssh-agent
데이터베이스에서 직접 키를 수신하고 해독할 수 있습니다.
답변2
파일은 응용 프로그램 간에 데이터를 교환하는 주요 수단입니다. 디스크 파일일 필요는 없습니다. 임시 저장소의 파일이나 파이프일 수 있습니다. ssh-add
키 파일이 비밀번호로 보호되지 않는 한, 키 파일을 표준 입력에 제공할 수 있습니다(그리고 키 파일은 암호화되어 저장되므로 비밀번호로 보호할 이유가 없습니다).
/run
또는 복잡한 작업을 수행하지 말고 ( /dev/shm
또는 /tmp
배포판에서 제공하는 모든 것) 과 같은 메모리 지원 파일 시스템에 파일을 쓰십시오 .
또는 외부 암호화 없이 개인 키 파일을 보관하되 비밀번호를 설정하세요. 무작위로 생성된 긴 비밀번호를 사용하고 해당 비밀번호를 데이터베이스에 저장하세요.
1 실험적으로 ssh-add
비밀번호로 보호되어 검색할 수 없는 키 파일(예: 명명된 파이프)이 차단됩니다.
답변3
죄송합니다. 답변은 아니지만 댓글이 너무 길어서 해당 댓글이 맞는 줄 알았습니다.
중요한 것은 암호화된 키를 데이터베이스에 저장하여 달성하려는 목표입니다.
임시 개인 키 파일에 대한 액세스 권한이 있는 공격자는 SSH 클라이언트 프로세스의 메모리를 읽을 수도 있습니다(따라서 어쨌든 키 데이터를 얻을 수 있음). 두 데이터 모두 본질적으로 동일한 액세스 권한을 가져야 하기 때문입니다. 즉, 파일을 숨기려고 합니다. 작동하지 않는 것 같습니다. 더 안전해지지 않습니다.
데이터베이스, 웹 애플리케이션 및 SSH 연결에 서로 다른 사용자를 사용하는 경우 데이터베이스에 키를 저장하고 웹 애플리케이션에서 암호를 해독한 후 SSH에 제공하면 프로세스 전반에 걸쳐 키가 전파될 뿐입니다. 벡터. 한 명의 사용자만 사용하여 이러한 모든 작업(db, app, ssh)을 수행하면 코드가 복잡해집니다.
유일한 장점은 시스템을 다른 호스트로 더 쉽게 이동할 수 있고 데이터베이스 데이터가 도난당했지만 웹 애플리케이션(암호 해독 알고리즘과 비밀번호가 포함된 AFAIU)은 도난당하지 않은 경우 잠재적으로 이득을 얻을 수 있다는 점인 것 같습니다. 하지만 이것이 가능합니까?
즉, 키를 보호하려면 ssh의 내부 암호화 키를 사용하여 서비스 시작 시 해당 키를 ssh 에이전트에 로드할 수도 있습니다(서비스가 중지되면 삭제하는 것을 잊지 마세요!). 하지만 ssh-agent는 키를 암호화되지 않은 상태로 메모리에 보관하므로 키를 읽을 수 있다는 점을 다시 한 번 기억하세요. 다시 말해보세요: 예이것해결하고 싶은 문제는 무엇입니까?
두 시스템 간의 통신만 보호해야 하는 경우,stunnel
SSH보다 더 나은 서비스를 제공할 수 있습니다.
마지막 질문은 다음과 같습니다.SSH 열기(가지고 다닐 수 있는), 이 옵션과 같이 다른 프로세스에서 키를 읽을 수 있도록 하는 간단한 패치를 작성하는 것은 ssh
매우 간단해야 합니다 .sshd
AuthorizedKeysCommand
답변4
저는 Python을 사용하여 키 쌍을 생성하고 이를 데이터베이스에 저장할 때 이 문제를 해결하려고 합니다. 다음은 ssh-agent
이를 실행하고 상호 작용하는 데 사용한 몇 가지 단계입니다 . Python으로 작성되었지만 아마도 다른 언어로 번역할 수 있을 것입니다. 또 다른 특징은 이들을 사용하지 않기 shell=True
때문에 인젝션 공격으로부터 더욱 안전하다는 점이다.
import subprocess
import os
sockfile = '/some/place.sock'
agent = subprocess.Popen(['ssh-agent',
'-D', # foreground mode
'-a', sockfile, # bind address (socket file)
])
subprocess.check_call(['ssh-add',
'-D', # delete all identities from the agent
],
env={'SSH_AUTH_SOCK': sockfile},
)
이것은 ssh-agent
우리 프로그램에 대해서만 작동하는 프로그램을 시작하고 이를 지웁니다(내 사용자 키를 여기에 로드하고 있다고 생각하지만 확실하지 않습니다.) SSH_AUTH_SOCK
일반적으로 설정되는 환경 변수 ssh-agent
(그러나 우리는 수동으로 설정합니다)가 제공됩니다. 다른 프로그램에.
다음으로 ssh-add
개인 키를 제공합니다(여기서는 문자열로 저장되어 있지만 dr.private_key
직렬화해야 하므로 ASCII로 인코딩합니다).
adder = subprocess.Popen(['ssh-add',
'-', # read key from stdin
],
env={'SSH_AUTH_SOCK': sockfile},
stdin=subprocess.PIPE,
)
adder.communicate(dr.private_key.encode('ascii'))
retval = adder.wait()
assert retval == 0 # added successfully
이제 SSH를 사용하는 일부 애플리케이션(예: Git)을 사용할 때마다 동일한 SSH 프록시 소켓을 사용하여 이를 참조합니다.
gitp = subprocess.Popen(
['git', '-C', os.path.abspath('../some-repo') ,'fetch'],
env={'SSH_AUTH_SOCK': sockfile},
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
print(gitp.communicate()[0].decode('ascii'))
그리고 그것은 훌륭하게 작동합니다. 유일한 "임시파일"은 사용된 소켓인데 ssh-agent
, 소유자만이 접근할 수 있도록 생성되며, 에이전트 종료 시 삭제된다.