Selenium初探之自動備份裝置配置檔案及上傳
*本文原創作者:hackerbaba,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載
一、背景介紹
在傳統的網路安全架構中,難免會有一些重要的安全裝置或是軟體配置需要定期備份,統一歸檔。一是為了滿足合規,二是在裝置變更出現問題的時候,能夠快速回滾。手工定期備份難免會有遺漏,且浪費大量人力。
為了滿足這一需求,我利用Selenium (瀏覽器自動化測試框架)實現這個自動備份功能,當然其他的python爬蟲模組(比如request)也能實現這個功能(大體步驟都差不多),這個後續會繼續分享給大家,這次就不在這裡討論。實現自動備份後,再利用python FTP模組實現統一歸檔到FTP伺服器。備份週期直接利用cron命令即可。既然有指令碼自然少不了是否備份成功告警,利用logging模組記錄日誌,然後再通過rsyslog或第三方轉發器傳至日誌分析平臺即可實現告警,我們公司由於使用的splunk,利用splunk forward傳輸日誌即可。有些人可能對Selenium不是太瞭解,下面我稍微簡單介紹一下Selenium。
二、Selenium+Chrome配置及功能說明
Selenium是一個瀏覽器自動化測試框架。Selenium測試直接執行在瀏覽器中,就像真正的使用者在操作一樣。Selenium在爬蟲中的運用主要就是查詢html相應元素並進行元素互動操作,常見的8種元素定位的方法如下:
find_element_by_name find_element_by_id find_element_by_xpath find_element_by_link_text find_element_by_partial_link_text find_element_by_tag_name find_element_by_class_name find_element_by_css_selector
其中最常用的就是find_element_by_name/id/xpath/link_text,其中xpath推薦使用瀏覽器外掛定位元素。火狐瀏覽器一般使用 firebug 和 firepath 定位元素;谷歌瀏覽器一般使用xpath helper外掛定位元素。
Windows/linux除了安裝Selenium模組外,一般需要下載瀏覽器對應的webdriver驅動到相應資料夾宣告並呼叫瀏覽器,一個簡單的示例如下:
from selenium import webdriver
browser = webdriver.Chrome() 或 browser =webdriver.Firefox() #呼叫谷歌或者火狐瀏覽器
browser.get(“ http://www.baidu.com “) #瀏覽器開啟百度
print(browser.page_source) #列印百度首頁的原始碼
browser.close() #關閉瀏覽器
在linux系統中,還需要宣告一些“無頭”配置,具體見實現見指令碼。
三、python+selenium+無頭Chrome具體實現指令碼
Python環境:3.7.0 selenium:3.141.0 chrome:72.0.3626.119
Webdriver下載地址 https://chromedriver.storage.googleapis.com/index.html
自動備份物件:某品牌WAF裝置,其他裝置更改IP地址、定位相關html元素即可。
#coding=utf-8 import os import time import logging import ftplib from ftplib import FTP from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys importKeys from selenium.webdriver.support.ui import Select from selenium.webdriver importDesiredCapabilities from selenium.webdriver.chrome.optionsimport Options Device = 'WAF'#定義裝置型別 IP = 'x.x.x.x'#目標IP dir_time = time.strftime('%Y-%m-%d',time.localtime()) #輸出當前"年-月-日"時間 dir_backup =f'/opt/sec_backup/{IP}_{Device}/{dir_time}' #chrome下載的地址備份檔案的路徑 log_name =f'/opt/sec_backup/log/{IP}/{dir_time}.log' #存放日誌檔案的路徑 if os.path.exists(dir_backup): pass else: os.mkdir(f'/opt/sec_backup/{IP}_{Device}/{dir_time}') #建立dir_backup路徑 host = 'X.X.X.X' port = 21 user = 'XXXX' pwd = 'XXXXX' #以上定義FTP伺服器相關資訊 logging.basicConfig(filename=log_name,level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) #定義日誌輸出格式 try: opts = Options() opts.headless=True opts.add_argument('--no-sandbox') opts.add_argument('--disable-gpu') capabilities = DesiredCapabilities.CHROME.copy() capabilities['acceptSslCerts'] = True capabilities['acceptInsecureCerts'] = True prefs = {'download.prompt_for_download': False, 'download.directory_upgrade': True, 'safebrowsing.enabled': False, 'safebrowsing.disable_download_protection': True} opts.add_experimental_option('prefs', prefs) driver = webdriver.Chrome(options=opts,desired_capabilities=capabilities) #以上是“無頭”的一些配置,具體就不一一展開 driver.implicitly_wait(10) #設定超時時間10秒鐘 driver.command_executor._commands["send_command"] =("POST",'/session/$sessionId/chromium/send_command') driver.desired_capabilities['browserName'] = 'ur mum' params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior':'allow', 'downloadPath': '%s' %dir_backup }} driver.execute("send_command", params) #Chrome下載備份檔案到dir_backup目錄 driver.get(f"https://{IP}/login/requireLogin") driver.find_element_by_id("username").send_keys("xxx") driver.find_element_by_id("password").send_keys("xxx") driver.find_element_by_id("loginButton").click() driver.find_element_by_id("one3").click() driver.find_element_by_id("two32").click() driver.switch_to.frame("mainFrame") driver.find_element_by_link_text("配置同步").click() driver.find_element_by_xpath("(//input[@id='tmp'])[2]").click() time.sleep(30) driver.switch_to.alert.accept() driver.find_element_by_xpath("//*[@id='backpointtable']/tbody/tr[2]/td[5]/img[3]").click() while True: if os.listdir(dir_backup) andos.listdir(dir_backup)[0].endswith('.wafc'): #備份週期是天,一天只生成一個固定目錄,裡面只有一個備份檔案,故判斷是否有檔案即可 logger.info('備份成功') break else: continue driver.find_element_by_link_text("配置同步").click() driver.find_element_by_xpath("//*[@id='backpointtable']/tbody/tr[2]/td[5]/img[4]").click() confirm2 = driver.switch_to.alert confirm2.accept() driver.quit() #logger.info('刪除舊備份成功') except Exception as e: logger.info(f"自動備份出現異常,異常內容:{e}") def ftpconnect(): ftp_server = host username = user password = pwd ftp = FTP() ftp.set_debuglevel(0) ftp.connect(ftp_server, 21) ftp.login(username, password) return ftp def uploadfile(): try: ftp = ftpconnect() remotepath = ftp.mkd(f'/{IP}-{Device}/{dir_time}') except: pass ftp.cwd(remotepath) bufsize = 1024 localfile = dir_backup + '/' + os.listdir(dir_backup)[0] remotefile = os.listdir(dir_backup)[0] print(localfile) fp = open(localfile, 'rb') ftp.storbinary('STOR ' + remotefile, fp, bufsize) #上傳本地localfile,至remotepath,並命名remotefile ftp.set_debuglevel(0) #關閉ftp的除錯模式,如果設定為2,則輸出詳細資訊 fp.close() if __name__ == '__main__': try: uploadfile() except Exception as e: logger.info(f"檔案上傳出現異常,異常內容:{e}") else: logger.info('檔案上傳成功')
四、效果圖