最近疫情虽有好转趋势,仍不可放松,很多企业不得不减少人员密度,或者直接在家远程办公。
可是某些行业由于保密性,如果不能保证远程办公时数据的安全,远程办公也就无法实现。
最近测试了jumpserver和teleport这两款开源堡垒机系统,能够用一个有公网IP的linux机器做堡垒,通过网页登录连接中转ssh或者rdp远程桌面,同时他们的权限分配、运维管理、操作记录等等也都很完善。
如果只是运维人员通过ssh连接其实还好,可是中国大多数人还是使用windows进行工作。而windows的rdp远程图像质量不佳,还会消耗大量带宽,一旦使用人数较多,难免有卡顿和马赛克问题。
不过在这非常时期,也能作为一个备选的方案。
不过对于注重数据安全的企业来说,只是禁用rdp远程的上传下载和剪贴板等功能,并不能保证数据安全,仍然存在通过截图或拍照的方式导致内部数据泄露的问题。
因此,我开始研究通过python添加屏幕水印的功能,检测RDP连接开启就显示屏幕水印,如果在公司办公则不需要显示。
水印本身通过tkinter库来制作,参考了Python 实现计算机屏幕水印一文。
import tkinter, win32api, win32con, pywintypes #生成重复文字,可更改间距 def get_replicate_text(text): i,space,str1,str2 = 0,70,"","" while (i <= 5): str1 = str1 + text + " "space i = i + 1 str2 = " "space + str1 + "\n\n\n\n" str1 = str1 + "\n\n\n\n" str1 = (str1 + str2) * 5 return str1 mytext = get_replicate_text('watermark') #水印重复文字设置 root = tkinter.Tk() width = win32api.GetSystemMetrics(0) height = win32api.GetSystemMetrics(1) root.overrideredirect(True) #隐藏显示框 root.geometry("+0+0") #设置窗口位置或大小 root.lift() #置顶层 root.attributes("-alpha",0.6) #全局透明度,用来设置水印文字透明 root.wm_attributes("-topmost", True) #始终置顶层 root.wm_attributes("-disabled", True) #禁止鼠标等与水印窗口交互 root.wm_attributes("-transparentcolor", "white")#白色背景透明 hWindow = pywintypes.HANDLE(int(root.frame(), 16)) exStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT win32api.SetWindowLong(hWindow, win32con.GWL_EXSTYLE, exStyle) label = tkinter.Label(text=mytext,compound = 'left',font=('Times New Roman','15'), fg='#d5d5d5', bg='white') label.pack() #显示
而判定当前账号是否是远程登录的方法是windows本身的quser命令,如果当前登录用户的会话名为rdp-tcp的话,就证明当前用户是通过RDP远程登录的,从而开启水印。
而只是能够自动开启水印显然是不够的,因为即使此服务在后台开机自启,仍然存在被人发现和关闭的风险,比如taskkill命令,或者在开始菜单中注销用户并在彻底注销前取消,后台水印进程都会被关闭。
因此有必要做成中心化的server/client服务,每个水印服务client启动时通过socket连接到server服务,在用户每次登陆(显示水印)、退出(关闭水印)时发送信息到server。
当某个socket连接断开时,就代表水印服务client被关闭,此时可以选择发送警告邮件到运维人员的邮箱,或者直接远程重启client服务,或者直接将该机器上的远程用户注销登录等。
下面先说说一对多的socket连接命令,首先是server端:
from socket import * from threading import Thread address = "127.0.0.1" port = 5432 buffsize = 1024 Msock = socket(AF_INET,SOCK_STREAM) Msock.bind((address,port)) Msock.listen(24) #set max connect 24 conn_list = [] #save connecting connect conn_dt = {} def tcplink(sock,addr): while True: try: #accept message and save recvData = sock.recv(buffsize).decode("utf-8") print(recvData,addr) if not recvData: break except: #when break,remove connect sock.close() print(addr,"offline") _index = conn_list.index(addr) conn_dt.pop(addr) conn_list.pop(_index) break def recs(): while True: clientsock,clientaddress = Msock.accept() if clientaddress not in conn_list: conn_list.append(clientaddress) conn_dt[clientaddress] = clientsock print("connect from:",clientaddress) #start thread t = Thread(target=tcplink,args=(clientsock,clientaddress)) t.start() if __name__ == __"main"__: recs()
然后是client端:
from socket import * def run(): ip = "127.0.0.1" port = "5432" buffsize = 1024 conn = socket(AF_INET,SOCK_STREAM) conn.connect((ip,port)) conn.send("hello,bitch") if __name__ == __"main"__: run()
如上,因为是一对多的模式,所以server端需要通过多线程创建并保持连接,client端主线程为水印,也需要单独一个线程连接server通信。
当用户登录、退出、或者client服务被关闭时,server端可以发送邮件通知运维人员,邮件发送部分代码如下:
from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr,formataddr import smtplib acccount = "yumefx@yumefx.com" password = "123456" #部分邮箱(例如qq邮箱)这里需要填写授权码,在邮箱客户端设置那里可以生成 toMailAddrs = ["admin@yumefx.com","develope@yumefx.com"] smtpServer = "smtp.yumefx.com" def formatAddress(s): name,addr = parseaddr(s) return formataddr((Header(name,"utf-8").encode(),addr)) def sendmail(title,text): server = smtplib.SMTP(smtpServer,25) #25是默认的smtp端口,有可能不同 server.set_debuglevel(1) server.login(acccount,password) msg = MIMEText(text,"plain","utf-8") msg["Form"] = formatAddress("Watermark Service<%s>" %acccount) msg["Subject"] = Header(title,"utf-8").encode() for ta in toMailAddrs: msg["To"] = formatAddress("SiteGroup<%s>" % ta) server.sendmail(acccount,ta,msg.as_string()) server.quit() sendmail("warning","watermark offline")
如果某个socket连接断开,那么可以由server运行下面的cmd命令重启client服务
wmic /node:192.168.1.10 /user:administrator /password:123456 process where name="watermark.exe" call terminate wmic /node:192.168.1.10 /user:administrator /password:123456 process call create "watermark.exe"
熟悉的wmic命令对吧,快去复习wmic命令详解及应用。
为什么是exe不是py,当然要打包好再用啊。pyinstaller-py脚本打包成exe。
至于怎么把这几块功能结合起来,请去全世界最大的直男交友平台github查看。
中国总是被他们最勇敢的人保护得很好。
《论中国》——基辛格
评论
244334 615596I believe this internet internet site contains quite superb composed articles posts . 887848
950304 472056excellent day, your website is really unquie. Anways, i do appreciate your work 866136
602518 191326This kind of lovely blog youve, glad I located it!?? 495669