所有ssh命令的本地时间戳记录?


12

如何保留我在其中使用的所有远程命令的本地时间戳记ssh(命令行openssh客户端始于bash)?

要求:

  • 必要:

    • 100%客户端,无需依赖服务器日志
    • 为每个用户配置或安装的日志存储在用户的主目录中。
    • 支持区分与多个用户和主机的多个同时会话。
    • 非侵入性(无需每次都激活它,并且不会严重干扰使用ssh)
  • 高优先级:

    • 没有记录输出或尽可能过滤掉
    • 密码条目未记录或文件已加密
    • 指示实际使用的命令(在完成制表符/历史记录,退格键,CTRL+ C等之后的操作)
  • 很高兴有:

    • 还记录链接会话中的命令(在远程sshsu <user>会话期间输入的命令)
    • 会话的开始和结束应被记录
    • 一个bash基于简单的,非root用户的解决方案将是最好的(也许是该命令的aliasbash包装脚本ssh?)

我的技能水平:

  • 我对编程并不陌生,但仍在学习bash和学习“ Linux方式”,因此,对带有简短说明的代码示例将不胜感激。

可能的策略

  • 键盘记录程序 -问题:记录密码,不记录选项卡/历史记录完成(请参阅glenn的回答
  • 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]

或者,也许会为每个会话创建一个单独的日志,并使用用于在文件顶部启动会话的命令行。


它还应该处理诸如nano或vim之类的编辑器
雏菊

Answers:


4

你的问题让我很感兴趣。我原本不想给出答案,但是我迷上了。

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命令),则在日志文件中将显示“ upt \ t”,而不是“正常运行时间”
  • 它会以“原始”模式捕获字符:如果用户是打字员,则^?在日志文件中会出现很多(退格字符)。

非常感谢您的回答。有趣的是,对于ssh客户端而言,似乎没有一个简单的答案。感谢您解释这些限制;我认为制表符补全/退格字符记录/密码记录足以阻止我经常使用它。这也使我对自己的优先事项进行了更多的思考,我将澄清问题中的那些内容。
Oleg 2014年

可以对生成的进程的输出进行解析,以提取所需的命令。您需要知道用户的提示才能使其变得更容易。
格伦·杰克曼(Glenn Jackman)2014年

我经常使用制表符补全。这是否意味着不会记录这些命令?
Oleg 2014年

啊,我明白你在说什么。如何解析输出?提示可以作为配置选项输入到某处。
Oleg 2014年

我在问题的底部添加了可能的解决方案列表。ssh ... | tee -ai <logfile>可以很好地安全记录输入和输出,但是我不知道如何在后台添加时间戳和/或过滤输出。
2014年

2

我目前正在使用下面的bash脚本。它有很多问题,但这是我发现的唯一解决方案,可以解决所有要求,优先级和“要拥有的东西”(至少在大多数情况下)。

该答案讨论了为什么在本地记录ssh会话如此困难。

到目前为止发现的脚本问题:

  1. 多行命令会导致问题:

    • 如果您翻阅远程历史记录中的多行项目(使用向上/向下键),它将记录一个历史项目而不是最新命令。您可以通过在使用任何多行命令后立即从bash历史记录中删除这些命令来避免这种情况。
    • 仅记录多行命令的第一行。
  2. 链接的会话(在远端使用sshsu命令)导致历史记录滚动以记录滚动通过的命令,而不是实际使用的命令

  3. 对于某些环境,可以改进正则表达式,并且可能需要对其进行修改:

    • 我通过cat -v在清洁之前转换非打印字符来作弊。因此,如果您曾经^[[在命令中使用过字符串,则可能会删除有效内容。
    • 有时,您会在命令之前获得额外的日志输入,例如,如果您快速浏览历史记录。通常在实际命令前跟一个“ ^ M”,因此如果需要可以将其删除。
    • 有时还会出现其他控制字符。我暂时将它们全部保留,直到我知道可以安全删除为止。我刚才提到的^ M对于检测无效的日志输入很有用,^ C会告诉您命令是否被中止。
    • 提示正则表达式可能需要针对特定​​提示进行修改,并且我可以想象不同的远程环境可能具有不同的控制字符模式。
  4. 没有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]

0

我的回答不太复杂,而且肯定不是键盘记录程序。我不认为服务器日志是独立的(这意味着所有操作都需要对服务器执行,所有日志都是服务器端日志),因此我认为一个好主意是传递给系统范围的bashrc提示命令,例如:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -t "$USER[$$] $SSH_CONNECTION")'

在debian中,您应该编辑文件:/etc/bash.bashrc,在centos中,文件:/ etc / bashrc

如果要开始记录您所在的会话,则必须来源已编辑的文件,例如执行:


source /etc/bash.bashrc

在Debian系统中或


source /etc/bashrc
在centos系统中。

从现在开始,每个ssh会话的每个命令都将记录在debian系统上的/ var / log / syslog中,以及centos系统上的/ var / log / messages中

如果您想将它们记录在一个单独的文件上而不与其他日志文件混淆,则可以使用:


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


该问题专门涉及在启动/本地/客户端计算机一侧记录ssh会话的问题,而不必(记住/允许)配置每个远程服务器,也不必手动从连接的所有远程服务器下载日志至。我认为您的答案虽然不能回答这个问题,但对有兴趣改进其服务器审核的人很有用,也许应该转到更相关的问题。
Oleg 2014年

0

怎么strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)样 这将记录所有ssh会话。您可能需要一个工具来随后解析日志,或者只使用grepawk等等。

  • -f:跟踪分叉的孩子
  • -ff:将每个孩子分别记录到 ssh_log.PID
  • -s8192:增加字符串记录限制(如果需要)
  • -T -ttt:自大纪元以来以秒为单位的微秒级标记
  • -p N:附加到pid N
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.