에서 사용하는 모든 원격 명령의 로컬 타임스탬프 기록을 어떻게 유지할 수 있습니까 ssh
(명령줄 openssh 클라이언트는 다음을 통해 시작됨 bash
)?
요구사항:
필수적인:
- 서버 로깅에 의존하지 않고 100% 클라이언트측
- 사용자의 홈 디렉터리에 저장된 로그를 사용하여 사용자별로 구성 또는 설치됩니다.
- 다양한 사용자 및 호스트와의 다중 동시 세션 구별을 지원합니다.
- 비침해적(매번 활성화할 필요가 없으며 SSH 사용을 크게 방해하지 않음)
높은 우선순위:
- 출력이 기록되지 않거나 최대한 필터링되지 않습니다.
- 비밀번호 항목이 기록되지 않거나 파일이 암호화됩니다.
- 실제 사용된 명령을 나타냅니다(탭/기록 완료, 백스페이스, CTRL+ C등이 처리된 후).
가져서 좋다:
- 연결된 세션의 명령도 기록합니다(원격
ssh
또는su <user>
세션 중에 입력된 명령). - 세션 시작 및 종료가 기록되어야 합니다.
- 단순한
bash
기반의 루트가 아닌 솔루션이 가장 좋습니다(아마도alias
명령bash
에 대한 래퍼 스크립트 일까요ssh
?)
- 연결된 세션의 명령도 기록합니다(원격
내 기술 수준:
- 나는 프로그래밍에 익숙하지 않지만 여전히
bash
"Linux 방식"을 배우고 있으므로 간단한 설명이 포함된 코드 샘플을 가장 높이 평가할 것입니다.
가능한 전략
- 키로거-- 문제: 비밀번호는 기록하지만 탭/기록 완료는 기록하지 않습니다(참조:글렌의 대답)
screen
초당 한 번씩 스크롤백 덤프를 수행하고diff
그 사이에서 새로운 스크롤백 라인을 찾습니다.-- 문제: 이것이 어떻게 유용하고 자동화된 방식으로 구현될 수 있습니까?ssh "$@" | tee >(some_cleaner_function >> $logfile)
-- 문제: 연결된 세션에서 여러 줄 명령이나 기록을 처리할 수 없습니다. 주의 깊게 정리가 필요합니다(내 답변 참조).- 위의 내용 중 일부를 조합한 것
예
다음 SSH 세션:
user@local:~$ ssh user@remote
Last login: Tue Jun 17 16:34:23 2014 from local
user@remote:~$ cd test
user@remote:~/test$ ls
a b
user@remote:~/test$ exit
~/logs/ssh.log
다음과 같은 로그가 발생할 수 있습니다 .
2014-06-17 16:34:50 [user@remote - start]
2014-06-17 16:34:51 [user@remote] cd test
2014-06-17 16:34:52 [user@remote] ls
2014-06-17 16:34:53 [user@remote] exit
2014-06-17 16:34:53 [user@remote - end]
또는 파일 상단에서 세션을 시작하는 데 사용되는 명령줄을 사용하여 각 세션에 대해 별도의 로그가 생성될 수도 있습니다.
답변1
나는 당신의 질문에 흥미를 느꼈습니다. 원래는 대답 안 하려고 했는데 푹 빠졌어요.
이것은 expect
실제로 키 로거를 사용합니다.
#!/usr/bin/expect -f
proc log {msg} {
puts $::fh "[timestamp -format {%Y-%m-%d %H:%M:%S}]: $msg"
}
set ssh_host [lindex $argv 0]
set ::fh [open "sshlog.$ssh_host" a]
log "{session starts}"
spawn ssh $ssh_host
interact {
-re "(.)" {
set char $interact_out(1,string)
if {$char eq "\r"} {
log $keystrokes
set keystrokes ""
} else {
append keystrokes $char
}
send -- $char
}
eof
}
log "{session ends}"
노트:
- 이름에 ssh 대상이 있는 파일에 추가됩니다.
- 이는 키 로거입니다. SSH 키를 설정하지 않은 경우 로그 파일에서 사용자 비밀번호를 얻습니다.
- 탭 완성으로 인해 실패합니다. 사용자가 명령을 입력하면 uptTab로그
uptime
파일에 "uptime"이 아닌 "upt\t"가 표시됩니다. ^?
"원시" 모드에서 문자를 가져옵니다. 사용자가 타이핑을 잘 못하는 경우 로그 파일에 많은 백스페이스 문자가 표시됩니다 .
답변2
현재 아래 bash 스크립트를 사용하고 있습니다. 많은 문제가 있지만 모든 요구 사항, 우선 순위 및 "있으면 좋은 것"(적어도 대부분의 경우)을 해결하는 유일한 솔루션입니다.
이 답변SSH 세션을 로컬로 로깅하는 것이 왜 그렇게 어려운지 설명합니다.
지금까지 발견한 스크립트의 문제점:
여러 줄 명령으로 인해 문제가 발생합니다.
- 원격 기록에서 여러 줄 항목을 페이지로 이동하는 경우(위/아래 키 사용) 최신 명령 대신 기록 항목이 기록됩니다. 당신은 이것을 피할 수 있습니다Bash 기록에서 삭제여러 줄 명령이 사용된 직후.
- 여러 줄 명령의 첫 번째 줄만 기록됩니다.
연결된 세션( 원격 끝에서
ssh
또는su
명령 사용)으로 인해 기록 스크롤이 사용된 실제 명령 대신 스크롤되어 전달된 명령을 기록하게 됩니다.정규식은 개선될 수 있으며 특정 환경에서는 수정해야 할 수도 있습니다.
- 나는 청소하기 전에 인쇄할 수 없는 문자를 변환하여 속임수를 씁니다
cat -v
. 결과적으로^[[
명령과 같은 문자열을 사용하면 유효한 콘텐츠가 제거될 수 있습니다. - 기록을 매우 빠르게 페이지를 넘기는 경우와 같이 명령 전에 추가로 기록된 입력을 받는 경우도 있습니다. 일반적으로 실제 명령 앞에 "^M"이 오므로 원하는 경우 제거할 수 있습니다.
- 다른 제어 문자가 나타나는 경우도 있습니다. 제거해도 안전한 것이 무엇인지 알 때까지 지금은 모두 그대로 두겠습니다. 방금 언급한 대로 ^M은 잘못된 기록 입력을 감지하는 데 유용하며 ^C는 명령이 중단되었는지 알려줍니다.
- 특정 프롬프트에 대해 프롬프트 정규식을 수정해야 할 수도 있으며, 원격 환경마다 제어 문자 패턴이 다를 수 있다고 상상할 수 있습니다.
- 나는 청소하기 전에 인쇄할 수 없는 문자를 변환하여 속임수를 씁니다
호스트 이름과 같은 SSH 명령 bash 완료가 없습니다.ssh
이 스크립트 에 별칭을 지정하면 bash 완료를 얻을 수 있습니다.alias ssh="sshlog"
스크립트 소스 및 설치:
설치하려면 다음을 ~/bin/sshlog에 붙여넣고 실행 가능하게 만듭니다. 로 전화하세요 sshlog <ssh command options>
. 선택적으로 사용자의 .bashrc 파일에서 'ssh'에 대한 별칭을 지정합니다.
#!/bin/bash
# A wrapper for the ssh command that produces a timestamped log of all ssh commands
declare -r logfile=~/logs/ssh.log
declare -r description="sshlog-${$} ${@}"
declare -r TAB=$'\t'
logdir=`dirname ${logfile}`
[ -d ${logdir} ] || mkdir "${logdir}";
clean_control_chars() {
while IFS= read -r line; do
# remove KNOWN control characters. Leave the rest for now.
# line=$(echo "${line}" | sed 's/\^\[\[K//g') # unkown control character: ^[[K
# line=$(echo "${line}" | sed 's/\^\[\[[0-9]\+[P]//g') # these are generated by up/down completion - e.g. ^[[2P
line=$(echo "${line}" | sed 's/\^\[\[[0-9]*[A-Z]//g') # all other ^[[..
# replay character deletions (backspaces)
while [[ $(echo "${line}" | grep -E --color=never '.\^H') != "" ]]; do
line=$(echo "${line}" | sed 's/.\^H//')
done
# remove common control characters
line=$(echo "${line}" | sed 's/\^M$//') # remove end of line marker from end
line=$(echo "${line}" | sed 's/^\^G//g') # remove start marker from start
# remove ^G from other locations - possibly a good idea
# line=$(echo "${line}" | sed 's/\^G//g')
# remove all other control characters - not recommended (many like ^C and ^M indicate which section was processed/ ignored)
# line=$(echo "${line}" | sed 's/\^[A-Z]//g')
echo ${line};
done
}
filter_output() {
while IFS= read -r line; do
# convert nonprinting characters and filter out non-prompt (in Ubuntu 14.04 tests, ^G indicates prompt start)
line=$(echo "${line}" | cat -v | grep -Eo '[\^][G].*[\$#].*')
[[ ${line} != "" ]] && echo "${line}"
done
}
format_line() {
while IFS= read -r line; do
raw=${line};
line=$(echo "${line}" | clean_control_chars);
prompt=$(echo "${line}" | grep -Po '^.*?(\$|#)[\s]*')
command=${line:${#prompt}}
timestamp=`date +"%Y-%m-%d %H:%M:%S %z"`
echo -e "${timestamp}${TAB}${description}${TAB}${prompt}${TAB}${command}"
done
}
echo "Logging ssh session: ${description}"
echo "[START]" | format_line >> ${logfile}
/usr/bin/ssh "$@" | tee >(filter_output | format_line >> ${logfile})
echo "[END]" | format_line >> ${logfile}
로그 내용 예:
2014-06-29 23:04:06 -0700 sshlog-24176 remote [START]
2014-06-29 23:04:12 -0700 sshlog-24176 remote oleg@remote:~$ cd test
2014-06-29 23:04:13 -0700 sshlog-24176 remote oleg@remote:~/test$ ls
2014-06-29 23:04:14 -0700 sshlog-24176 remote oleg@remote:~/test$ exit
2014-06-29 23:04:14 -0700 sshlog-24176 remote [END]
답변3
어때요 strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)
? 그러면 모든 SSH 세션이 기록됩니다. 이후에 로그를 구문 분석하거나 등을 사용하는 도구가 필요할 수 있습니다 grep
.awk
-f
: 분기된 자식 추적-ff
: 각 하위 항목을 개별적으로 기록합니다.ssh_log.PID
-s8192
: 문자열 로깅 제한을 늘립니다(필요한 경우).-T -ttt
: Epoch 이후 초 단위의 마이크로초 스탬핑-p N
: pid에 첨부N
답변4
나는 덜 복잡한 대답을 가지고 있으며 확실히 키로거는 아닙니다. 나는 서버 로그에 독립적이라는 점을 이해하지 못합니다(이는 모든 작업이 서버에 수행되어야 하고 모든 로그가 서버 측 로그라는 것을 의미합니다). 따라서 시스템 전체에 전달하는 것이 좋은 생각이라고 생각했습니다 bashrc 다음과 같은 프롬프트 명령:
PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -t "$USER[$$] $SSH_CONNECTION")'
데비안에서는 /etc/bash.bashrc 파일을 편집해야 하고, 센토스에서는 /etc/bashrc 파일을 편집해야 합니다.
현재 세션에 대한 로깅을 시작하려면 편집한 파일을 소스로 가져와야 합니다. 예를 들어 다음을 실행합니다.
source /etc/bash.bashrc
데비안 시스템에서 또는
source /etc/bashrc
센토스 시스템에서.
이제부터 모든 SSH 세션의 모든 명령은 다음 위치에 기록됩니다./var/log/syslog데비안 시스템과/var/log/메시지센토스 시스템에서.
별도의 파일에 기록하고 다른 로그 파일과 혼동하지 않으려면 다음을 사용할 수 있습니다.
PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
이전 PROMPT_COMMAND 예제 대신 필요에 따라 rsyslogd를 구성하십시오.
예를 들어 Debian 시스템에서는 다음을 편집합니다./etc/rsyslog.conf파일: 줄 변경:
.;auth,authpriv.none -/var/log/syslog
에게
.;auth,authpriv.none,local6 -/var/log/syslog
파일 끝에 다음 줄을 추가합니다.
local6.info /var/log/history.log
그런 다음 다음을 실행하십시오.
touch /var/log/history.log && /etc/init.d/rsyslog restart