




















ssh-monitor.sh
#!/bin/bash SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" # 配置文件路径 CONFIG_FILE="${SCRIPT_DIR}/ssh-login-sessions.conf" # 日志文件路径 LOG_FILE="/var/log/ssh-monitor.log" # ==================== 微信推送配置 ==================== WXPUSHER_APP_TOKEN="xxxxxx" WXPUSHER_UID="xxxxxx" # 确保配置文件和日志文件存在 touch "$CONFIG_FILE" "$LOG_FILE" # 微信推送函数 send_wx_message() { local summary="$1" local content="$2" curl -s -H 'Content-Type: application/json' \ -XPOST https://wxpusher.zjiecode.com/api/send/message \ -d "{ \"appToken\":\"${WXPUSHER_APP_TOKEN}\", \"content\":\"$content\", \"summary\":\"$summary\", \"contentType\":3, \"uids\":[\"${WXPUSHER_UID}\"] }" > /dev/null 2>&1 } # 获取sessionid的函数 get_sessionid() { local pid=$1 if [ -f "/proc/$pid/sessionid" ]; then cat "/proc/$pid/sessionid" 2>/dev/null || echo "unknown" else echo "unknown" fi } # 解析登录信息的函数 parse_login_info() { local json_line="$1" local pid=$(echo "$json_line" | jq -r '._PID') local message=$(echo "$json_line" | jq -r '.MESSAGE') # 从MESSAGE中提取用户名和IP if [[ "$message" == Accepted* ]]; then # Accepted publickey for root from 192.168.100.53 port 11105 ssh2: ... local username=$(echo "$message" | grep -oP 'for \K[^ ]+') local ip=$(echo "$message" | grep -oP 'from \K[^ ]+') # 提取登录方式 (publickey / password / keyboard-interactive 等) local auth_method=$(echo "$message" | grep -oP 'Accepted \K[^ ]+') # 获取当前时间 local login_time=$(date '+%Y-%m-%d %H:%M:%S') # 获取sessionid local sessionid=$(get_sessionid "$pid") # 返回JSON格式的登录信息 echo "{\"pid\":\"$pid\",\"username\":\"$username\",\"ip\":\"$ip\",\"login_time\":\"$login_time\",\"sessionid\":\"$sessionid\",\"auth_method\":\"$auth_method\"}" fi } # 解析退出信息的函数 parse_logout_info() { local json_line="$1" local pid=$(echo "$json_line" | jq -r '._PID') local message=$(echo "$json_line" | jq -r '.MESSAGE') if [[ "$message" == "Disconnected from user"* ]]; then # Disconnected from user root 192.168.100.53 port 11105 local username=$(echo "$message" | grep -oP 'user \K[^ ]+') local ip=$(echo "$message" | grep -oP '\K[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+') echo "{\"pid\":\"$pid\",\"username\":\"$username\",\"ip\":\"$ip\"}" fi } # 记录登录事件 handle_login() { local login_info="$1" local pid=$(echo "$login_info" | jq -r '.pid') local username=$(echo "$login_info" | jq -r '.username') local ip=$(echo "$login_info" | jq -r '.ip') local login_time=$(echo "$login_info" | jq -r '.login_time') local sessionid=$(echo "$login_info" | jq -r '.sessionid') local auth_method=$(echo "$login_info" | jq -r '.auth_method') echo "login_info: $login_info" # 写入配置文件 echo "$pid|$login_info" >> "$CONFIG_FILE" # 写入日志文件 echo "[LOGIN ] $login_time - User: $username, IP: $ip, PID: $pid, SessionID: $sessionid, AuthMethod: $auth_method" >> "$LOG_FILE" # 发送微信通知 local summary="✅ SSH登录通知 - $ip" local content="" content+="| 字段 | 信息 |\n" content+="|------|------|\n" content+="| 用户名 | **$username** |\n" content+="| IP地址 | \`$ip\` |\n" content+="| 登录时间 | $login_time |\n" content+="| PID | \`$pid\` |\n" content+="| SessionID | \`$sessionid\` |\n" content+="| 认证方式 | \`$auth_method\` |\n" send_wx_message "$summary" "$content" echo "✅ 登录事件已记录 - PID: $pid, User: $username" } # 处理退出事件 handle_logout() { local logout_info="$1" local pid=$(echo "$logout_info" | jq -r '.pid') local username=$(echo "$logout_info" | jq -r '.username') local ip=$(echo "$logout_info" | jq -r '.ip') # 从配置文件中查找对应的登录记录 local login_line=$(grep "^$pid|" "$CONFIG_FILE" | tail -1) if [ -n "$login_line" ]; then # 提取登录信息 local login_info=$(echo "$login_line" | cut -d'|' -f2-) local login_time=$(echo "$login_info" | jq -r '.login_time') local sessionid=$(echo "$login_info" | jq -r '.sessionid') # 计算连接时间 local logout_time=$(date '+%Y-%m-%d %H:%M:%S') local login_epoch=$(date -d "$login_time" +%s) local logout_epoch=$(date -d "$logout_time" +%s) local duration=$((logout_epoch - login_epoch)) local duration_str="" if [ $duration -ge 3600 ]; then duration_str="$((duration/3600))小时$(((duration%3600)/60))分钟" elif [ $duration -ge 60 ]; then duration_str="$((duration/60))分钟$((duration%60))秒" else duration_str="${duration}秒" fi # 写入日志文件 echo "[LOGOUT] $logout_time - User: $username, IP: $ip, PID: $pid, Login: $login_time, Duration: $duration_str" >> "$LOG_FILE" # 从配置文件中删除该记录 sed -i "/^$pid|/d" "$CONFIG_FILE" # 发送微信通知 local summary="❌ SSH退出通知 - $ip" local content="" content+="| 字段 | 信息 |\n" content+="|------|------|\n" content+="| 用户名 | **$username** |\n" content+="| IP地址 | \`$ip\` |\n" content+="| 登录时间 | $login_time |\n" content+="| 退出时间 | $logout_time |\n" content+="| 连接时长 | **$duration_str** |\n" content+="| PID | \`$pid\` |\n" content+="| SessionID | \`$sessionid\` |\n" send_wx_message "$summary" "$content" echo "❌ 退出事件已记录 - PID: $pid, User: $username, Duration: $duration_str" else # 如果没有找到登录记录,只记录退出信息 echo "[LOGOUT] $(date '+%Y-%m-%d %H:%M:%S') - User: $username, IP: $ip, PID: $pid (no login record found)" >> "$LOG_FILE" echo "❌ 退出事件 - PID: $pid (未找到登录记录)" fi } # 主循环 echo "开始监控SSH登录/退出事件..." echo "配置文件: $CONFIG_FILE" echo "日志文件: $LOG_FILE" journalctl _COMM=sshd -n 0 -f -o json | while read -r line; do message=$(echo "$line" | jq -r '.MESSAGE') # 处理登录事件 if [[ "$message" == Accepted* ]]; then login_info=$(parse_login_info "$line") if [ -n "$login_info" ]; then handle_login "$login_info" fi # 处理退出事件 elif [[ "$message" == "Disconnected from user"* ]]; then logout_info=$(parse_logout_info "$line") if [ -n "$logout_info" ]; then handle_logout "$logout_info" fi fi done
这是一个 SSH 登录/退出实时监控脚本,主要功能如下:
表格
| 功能 | 说明 |
|---|---|
| 实时监控 | 通过 journalctl 实时监听 sshd 服务的日志事件 |
| 登录检测 | 捕获 SSH 成功登录事件(Accepted 关键字) |
| 退出检测 | 捕获 SSH 断开连接事件(Disconnected from user) |
| 会话追踪 | 通过 PID 和 SessionID 匹配登录和退出事件,计算连接时长 |
| 微信推送 | 使用 WxPusher 服务发送登录/退出通知到微信 |
| 日志记录 | 将事件记录到 /var/log/ssh-monitor.log |
登录时:提取用户名、IP、PID、SessionID → 写入配置文件 → 发送微信通知
退出时:通过 PID 查找对应登录记录 → 计算连接时长 → 发送微信通知(含时长统计)→ 清理配置记录
ssh-login-sessions.conf - 存储活跃会话信息(PID 与登录详情映射)
/var/log/ssh-monitor.log - 持久化日志记录
适合需要 实时掌握服务器 SSH 访问情况 的场景,如:
云服务器安全监控
运维审计追踪
异常登录告警
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。