如果你服务器被入侵了,该怎么做才能让自己第一时间知晓?

答案很多,其中一个方法是ssh登陆后发送报警信息给相关人员。

ssh远程登陆自身是可以设置提示消息的,比如sshd_config的Banner,不过本文描述另外方法,通过/etc/profile设置。

/etc/profile这个文件是每个用户登录时都会运行的环境变量设置,当用户第一次登录时,该文件被执行, 并从/etc/profile.d目录的配置文件中搜集shell的设置。

依此,我们写个shell脚本在每次远程登陆终端、复制终端时报警。

环境要求:

  1. 安装jq、screen软件包: yum -y install jq screen

  2. 部署脚本,比如/data/public/LoginAlert.sh

  3. /etc/profile追加报警脚本:

    比如 screen -fa -d -m -S WL sh /data/public/LoginAlert.sh(shell版本)

    比如 screen -fa -d -m -S WL python /data/public/LoginAlert.py(python版本)

shell版本,LoginAlert.sh脚本内容如下:

#!/bin/bash
# Author: www.saintic.com
# Email: staugur@saintic.com
# Date: 2017-08-11
# Docs: 登陆(新开终端或者复制终端)触发报警消息

#require jq
if [ ! -f $(which jq) ];then
    yum -y install jq
fi

#Geo2IP by Legion(http://www.dwhd.org/)
eval `curl -s "http://ip.taobao.com/service/getIpInfo.php?ip=${SSH_CLIENT%% *}" | jq . | awk -F':|[ ]+|"' '{if($3~/^(country|area|region|city|isp)$/){print $3"="$7}}'`

if [ $(last $USER |grep "still logged in" |wc -l) != "0" ];then
    isOnline="会话中"
else
    isOnline="已离线"
fi

hostIps="$(ip addr|grep inet|grep -v 127.0.0.1 |awk '{print $2}' |awk -F / '{print $1}')"
area="${country} ${area} ${region} ${city} ${isp}"
loginTime=$(date "+%Y-%m-%d %H:%M:%S")
#html mail content
msgContent="<div>
<h3>服务器SSH登陆提示</h3>
<p>服务器主机名: `hostname`</p>
<p>服务器IP地址: ${hostIps}</p>
<p>登录用户:     ${USER}</p>
<p>登陆状态:     ${isOnline}</p>
<p>登录端口:     ${SSH_CLIENT##* }</p>
<p>登录来源IP:   ${SSH_CLIENT%% *}</p>
<p>登陆IP归属地: ${area}</p>
<p>最后登录时间: ${loginTime}</p>
</div>
"

if [ ! -z "${SSH_CLIENT%% *}" ]; then
    # 执行报警任务
    # 发送邮件、微信,记录日志等
    :
fi

python版本,LoginAlert.py脚本内容如下:

# coding: utf8
# Author: www.saintic.com
# Email: staugur@saintic.com
# Date: 2017-08-14
# Docs: 登陆(新开终端或者复制终端)触发报警消息

import os
import sys
import json
import time
import socket
import urllib
import urllib2
reload(sys)
sys.setdefaultencoding('utf-8')

getHeader = lambda: {
    'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
    'Authentication': "此处头部认证信息"
}

def getNowTime():
    return time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))

def get(url, use_header=True):
    request = urllib2.Request(url, getHeader() if use_header else None)
    response = urllib2.urlopen(request)
    return json.loads(response.read())

def post(url, data, use_header=True):
    """ POST请求 """
    if isinstance(data, dict):
        data = urllib.urlencode(data)  # 将字典以url形式编码
    request = urllib2.Request(url, data, getHeader() if use_header else None)
    response = urllib2.urlopen(request)
    return json.loads(response.read())

def getArea(ip):
    url = "http://ip.taobao.com/service/getIpInfo.php?ip=%s" %ip
    try:
        data = get(url, use_header=False)
    except Exception,e:
        raise
    else:
        if data.get("code") == 0:
            data = data['data']
            return u"%s %s %s %s" %(data['country'], data['region'], data['city'], data['isp']), u"%s%s%s" %(data["country"], data['city'], data["isp"])
        else:
            raise ValueError

if __name__ == "__main__":
    try:
        clientIp, clientPort, serverIp, serverPort = os.getenv("SSH_CONNECTION").split()
    except AttributeError,e:
        raise
    hostname = socket.gethostname()
    username = os.getenv("USER")
    loginTime = getNowTime()
    EmailClientIpArea, WxClientIpArea = getArea(clientIp)
    isOnline = u'会话中' if os.system('last %s |grep "still logged in" &> /dev/null' %username) == 0 else u'已离线'
    # 定义发送邮件内容
    EmailMsgContent = u"""<div>
<h3>服务器SSH登陆提示</h3>
<p>服务器主机名: %s</p>
<p>服务器IP地址: %s</p>
<p>登录用户:     %s</p>
<p>登录来源IP:   %s</p>
<p>登陆IP归属地: %s</p>
<p>当前是否在线: %s</p>
<p>最后登录时间: %s</p>
</div>""" %(hostname, serverIp, username, clientIp, EmailClientIpArea, isOnline, loginTime)
    # 定义发送微信内容
    WxMsgContent ='''[Server SSH Prompt]\n\tHostName: %s\n\tServerIps: %s\n\tLoginUser: %s\n\tLoginSourceIP: %s\n\tLoginSourceIpArea: %s\n\tLastLoginTime: %s''' %(hostname, serverIp, username, clientIp, WxClientIpArea, loginTime)
    # 执行报警任务
    # 发送邮件、微信,记录日志等

·End·