yield-bytes

沉淀、分享与无限进步

堡垒机系统自定义Chrome代填程序开发

  企业内部有多个业务系统、管理系统,而这些系统相互独立,也无相关审计工具对操作人员进行审计,使用人员或者管理员在对账户等也存在一定疏忽,为加强网络安全以及保证内部信息安全,一般都要求这些管理系统接入堡垒机,堡垒机的审计原理:使用人员登录堡垒机系统,选中要登录的管理系统,堡垒机自动打开远程桌面,并代自动填入需要访问系统的账户和密码,这一过程对使用者透明,但堡垒机可通过录制使用者操作视频以及记录相关登入登出操作,达到对多个管理系统统一管理。

  关键功能配置在此:

  需在堡垒机系统上配置纳入审计的URL、账号和密码,其自带功能仅支持ie浏览器登录,而内部使用多个系统已不支持ie或者IE体验极差(包括旧管理系统和新管理系统),在应用类型选项仅有“IE代填以及自定义代填”两项选择,却没有类似“IE代填、Chrome代填、FireFox代填这些选项”, 而实际使用场景为使用Chrome浏览器代填,堡垒机厂家提供的自定义代填功能竟然无相关程序。

img点击并拖拽以移动

  如上图:厂家提供的默认选项IE代填,无需给出账户以及密码输入框的Xpath,即可实现通过IE打开相应web管理页面,但仅限IE打开!

img点击并拖拽以移动

  选择自定义代填,从界面选项来看,它仅提供目标地址url、登录账户、登录密码,如果要用chrome打开该url,首先要解决的是如何定位账户输入框位置和密码输入框位置,以便使用selenium打开webdriver定位到相应元素并自动填入信息。显然厂家无法提供该脚本,需自行开发!故需构造类似这样的脚本应用路径:

python autoFillingIn.py -url ** -user ** -psw ** -wait ** -hup ** -hpp ** -lp** -al **

其中-hup –hpp这两个入参为用户名输入框的xpath和密码输入框的xpath

堡垒机通过打开远程桌面后并运行该autoFillingIn.py,该程序通过入参调用chrome driver.exe从而打开chrome浏览器

以下为开发过程:

(1)环境准备:

由堡垒机打开的远程桌面所在服务器需安装python3.5环境、selenium库,以及chrome driver.exe

chromedriver下载

在阿里的镜像源:http://npm.taobao.org/mirrors/chromedriver/2.8/

chromedriver_win32.zip (可适用32位和64位windows)

selenium离线安装包

git clone https://github.com/SeleniumHQ/selenium.git

里面已有setup.py,将该离线包上传到远程桌面所在服务器

python setup.py install

注:如果使用其他浏览器例如Firefox、Edge 、Safari,可在以下官网下载相应driver

https://pypi.org/project/selenium/

(2)建议将chromedriver.exe和autoFillingIn.py放在同一目录下

这里放在c:\ chromeTools目录下

程序逻辑如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import os
import re
import time
import argparse
from selenium import webdriver

def keep_double_quotes(xpath):
"""
通过Chrome右键Copy Xpath获取目标url账户、密码、登录按钮输入框的Xpath有两种通用形式:
第一种在其html元素显示给出id值的://*[@id="usernameInput"] 以及 //*[@id="loginForm"]/fieldset/div[1]/input
第二种在其html元素没有id索引的:/html/body/form/table[1]/tbody/tr[5]/td[3]/input 或 /html/body/form/table[1]/tbody/tr[5]/td[3]/img
对于第一种Xpath,当使用入参 -up //*[@id="login_input"]时,会被argparse解析为 //*[@id=login_input],双引号没了!因此需要还原输入参数的格式,
否则find_element_by_xpath将无法定位,无法实现自动代填
该bug相对隐藏!
"""
m=re.search(r'=(.*?)\]',xpath)
if m:
id_name=m.group(1)
quotes_id_name='"'+id_name+'"'
double_quotes_path=re.sub(r'{}'.format(id_name),quotes_id_name,xpath)
return double_quotes_path
else:
return xpath

parser=argparse.ArgumentParser(description='自动代填')
parser.add_argument('-url',type=str,required=True,help='网站url,支持http和https')
parser.add_argument('-user',type=str,required=True,help='用户名')
parser.add_argument('-psw',type=str,required=True,help='密码')
parser.add_argument('-wait',type=int,default=5,help='网页加载等待秒数,保证元素加载出来后才能定位成功')


parser.add_argument('-up',type=keep_double_quotes,help='用户input提示元素的Xpath,取第一个input元素的id,style为"display: block;",如没有该id,则可忽略该-up选项')
parser.add_argument('-hup',type=keep_double_quotes,required=True,help='用户input存放用户名元素的Xpath,style为"display: none;",表示隐藏用户名输入')


parser.add_argument('-pp',type=keep_double_quotes,help='密码input提示元素的Xpath,取第一个input元素的id,style为"display: block;",如没有该id,则可忽略该-pp选项')
parser.add_argument('-hpp',type=keep_double_quotes,required=True,help='密码input真实密码填入元素的Xpath,style为"display: none;",表示隐藏密码输入')

parser.add_argument('-lp',type=keep_double_quotes,help='登录按钮的Xpath,使用Chrome的Copy Xpath定位元素路径')
parser.add_argument('-al',type=str,help='指定是否自动登录,如指定自动,填入Y或y,如需要填入验证码、短信等二次认证的输入框,请填入N或n')


# 获取输入参数
inputs=parser.parse_args()
target_url=inputs.url
username=inputs.user
password=inputs.psw
sleep_time=inputs.wait
u_inp=inputs.up
hidden_u_inp=inputs.hup
psw_inp=inputs.pp
hidden_psw_inp=inputs.hpp
login_input=inputs.lp
auto_login=inputs.al

# 获取chrome_driver所在路径
chrome_name = 'chromedriver.exe'
dir_name = os.path.dirname(os.path.abspath(__file__))
chrome_driver_path = os.path.join(dir_name, chrome_name)


# 添加chrome的一些优化设置例如不弹出无意义的提示栏、容许不安全访问、最大窗口访问、禁止gpu加速,
# 如不设置,Chrome会弹出一些警告栏甚至提示安全禁止打开url,将无法自动代填或自动代填后自动登入系统进入首页
options=webdriver.ChromeOptions()
options.add_argument('--disable-popup-blocking')
options.add_argument('--disable-infobars')
options.add_argument('--allow-running-insecure-content')
options.add_argument('--start-maximized')
options.add_argument('--disable-gpu')
driver=webdriver.Chrome(chrome_driver_path,chrome_options=options)

# Chrome浏览器打开一个窗口并打开该url
driver.get(target_url)

# 等待
time.sleep(sleep_time)

# 定位相关输入框或按钮位置并填入值
selector=driver.find_element_by_xpath


# 用户名含有隐藏输入时,有两个input id,需要对第一个input进行focus
if u_inp:
u_inp_selector=selector(u_inp)
driver.execute_script("arguments[0].focus();",u_inp_selector)


# 用户名输入框第二个input id,隐藏输入用户名的id,也要对其进行focus
hidden_u_inp_selector=selector(hidden_u_inp)
driver.execute_script("arguments[0].focus();", hidden_u_inp_selector)
hidden_u_inp_selector.send_keys(username)


# 密码含有隐藏输入时,有两个input id,需要对第一个input进行focus
if psw_inp:
psw_inp_selector=selector(psw_inp)
driver.execute_script("arguments[0].focus();",psw_inp_selector)


# 密码输入框第二个input id,隐藏输入用户名的id,也要对其进行focus
hidden_psw_inp_selector=selector(hidden_psw_inp)
driver.execute_script("arguments[0].focus();", hidden_psw_inp_selector)
hidden_psw_inp_selector.send_keys(username)



login=selector(login_input)

# 是否自动登录
if auto_login in ('Y','y'):
login.click()
else:
pass

点击并拖拽以移动

这里为何不设计为以下代码结构:

def auto_filling_in(**kargs):

​ pass

if name==”main”:

​ 获取入参

​ 调用auto_filling_in(**kargs)

因为使用该形式运行时,selenium会以子进程运行chromedriver.exe

if name==”main”:以下的代码作为父进程

而父进程在获取入参和调用auto_filling_in()后会结束,导致子进程运行的chrome也退出

(3)程序使用说明

最后在堡垒机上的配置该脚本:

应用路径:c:\ chromeTools\ autoFillingIn.py

运行参数:-url %Target -user %Username -psw %Password -wait 5 -fup /html/body/form/table[1]/tbody/tr[5]/td[1]/input -fpp /html/body/form/table[1]/tbody/tr[5]/td[4]/input -lp /html/body/form/table[1]/tbody/tr[5]/td[5]/img -al Y

登录地址:需要审计的管理系统url

登录账户:账户名

登录密码:密码

以上部分参数说明:

-fup账户输入框Xpath: /html/body/form/table[1]/tbody/tr[5]/td[1]/input,若为隐藏元素,则需要加入up选项

-fpp密码输入框Xpath: /html/body/form/table[1]/tbody/tr[5]/td[4]/input,若为隐藏元素,则需要加入pp选项

-lp登录输入框Xpath: /html/body/form/table[1]/tbody/tr[5]/td[5]/img

==重点内容==:

以上都是基于用户输入框和密码输入框都为输入字符可见的条件下,可以代成功,但是对于用户名、密码输入框设为输入字符隐藏时,需要加入以下两个选项才能定位到元素并正确代填,需要将鼠标先focus到用户名输入框或者密码输入框。

-up账户输入框Xpath: /html/body/form/table[1]/tbody/tr[5]/td[2]/input

-pp密码输入框Xpath: /html/body/form/table[1]/tbody/tr[5]/td[3]/input

(4) 运行效果:

img点击并拖拽以移动

img点击并拖拽以移动

​ 任务栏开启了两个远程桌面窗口,一个是autoFillingIn.py运行窗口,另一个为chrome打开的被审计web系统

​ 综上,最关键的设计:入参双引号处理,以及wait等待页面加载完毕的时间,因为某些旧管理系统服务器性能较低,打开页面慢,容易导致selenium无法定位元素位置。另外对于有验证码、短信等二次认证的web管理页面,自动登录选项 -al 要设为N或n,即不自动登录到首页,由使用人员自行填入验证码(账户和密码已经后台自动填到输入框内,无需再填入,除非使用人刷新了以打开的登录窗口,那么账户和密码输入框会被清空)。

​ 由于解决了argparse对入参Xpath字符串路径问题,本文的解决方案适用所有管理系统需要通过Chrome自动代填达到审计目的场景,之前在全网以及检索国外论坛,都未找到合适参考的方案,用了几天时间自行研究到部署可用,恰好满足实际场景(否则堡垒机系统使用受限,而且厂家无法提供该技术支持!)。在这里,也要介绍国内也有非常出色的开源堡垒机系统例如:Jumpserver,使用python+django开发(个人擅长的技术栈),而且该开源堡垒机系统还符合4A(认证Authentication、账号Account、授权Authorization、审计Audit)的专业运维审计系统,可docker化部署!

Jumpserver的官网:http://www.jumpserver.org/

github:https://github.com/jumpserver/jumpserver

相关开源堡垒机系统的对比参考文章:

https://blog.csdn.net/enweitech/article/details/88840456