在渗透行业提及web的话,主要是客户端角度,常见的例子就是爬虫,但为了力求入门,我们简单梳理一下web服务器端,时间关系不做深层拓展。
一、服务器端
二、客户端
一、服务器端
先来简单梳理下几个概念:
CGI
CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户端HTML页面的接口,CGI程序可以是Python脚本,PERL脚本,SHELL脚本,C或者C++程序等。它会负责生成动态内容,然后返回给服务器,再由服务器转交给客户端。但在每次产生请求时,服务器都会fork and exec,每次都会有一个新的进程产生,开销较大,基本淘汰。
WSGI
(Web Server Gateway Interface),WSGI是作为Web服务器与Web应用程序或应用框架之间的一种低级别的接口,以提升可移植Web应用开发的共同点。WSGI是基于现存的CGI标准而设计的,可以看作是在CGI标准上的一个封装。
所以、我们在此选择WSGI作为web初步学习,首先选写一个函数用以实现基本逻辑,命名为webdemo
:
#webdemo
def rabbit(env, start_response):
path = env['PATH_INFO'] #获取路径参数
if path == '/rabbit':
start_response('200 OK', [('Content-Type', 'text/html')])
body = '<h1>Hello,rabbit!</h1>'
return [body.encode()]
if path == '/':
start_response('200 OK', [('Content-Type', 'text/html')])
body = '<h1>Hello,But who are U!</h1>'
return [body.encode()]
else:
start_response('200 OK', [('Content-Type', 'text/html')])
body = '<h1>Sorry,Forget it!</h1>'
return [body.encode()]
其中,HTTP请求的所有输入信息都可以通过env获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。
然后再写一个一个服务模块,用以启动WSGI服务,并调用我们刚刚写的处理函数:
from wsgiref.simple_server import make_server
from webdemo import rabbit
httpd = make_server('', 8000, rabbit)
print('Serving HTTP on port 8000...')
httpd.serve_forever()
#输出:
Serving HTTP on port 8000...
127.0.0.1 - - [28/Jan/2019 10:46:01] "GET / HTTP/1.1" 200 29
127.0.0.1 - - [28/Jan/2019 10:46:01] "GET /favicon.ico HTTP/1.1" 200 25
127.0.0.1 - - [28/Jan/2019 10:49:42] "GET /rabbit HTTP/1.1" 200 22
127.0.0.1 - - [28/Jan/2019 10:49:43] "GET /favicon.ico HTTP/1.1" 200 25
127.0.0.1 - - [28/Jan/2019 10:49:49] "GET /233333 HTTP/1.1" 200 25
127.0.0.1 - - [28/Jan/2019 10:49:49] "GET /favicon.ico HTTP/1.1" 200 25
其中wsgiref是官方给出的一个实现了WSGI标准用于演示用的简单Python内置库,它实现了一个简单的WSGI Server和WSGI Application(在simple_server模块中),主要分为五个模块:simple_server, util, headers, handlers, validate。
浏览器写到这里,我们遇上了一个新的烦恼,我们这里只是一个简单的响应,如果是复杂响应,再加上上百甚至上千条路径,分布着不同的功能,我们也要通过一层一层的判断它的请求方式、请求路径么?
所以我们需要在WSGI接口之上能进一步抽象,让我们专注于用一个函数处理一个URL,至于URL到函数的映射以及服务响应问题,就交给Web框架来做。
于是,就引出了web框架的概念,近些年来随着python排名的飙升,框架也着实不少:CubicWeb,Django,Web2py,Weppy、Zope2、 Bottle,CherryPy,Falcon,Flask,Pyramid,Tornado,Web.py、Wheezy.web……
作为入门非开发需要,我们选择轻型框架flask简单演示,老规矩,改写上述例子:
from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET'])
def home():
body = '<h1>Hello,But who are U!</h1>'
return body
@app.route('/rabbit', methods=['GET'])
def rabbit():
body = '<h1>Hello,rabbit!</h1>'
return body
@app.errorhandler(404)
def miss(e):
body = '<h1>Sorry,Forget it!</h1>'
return body
if __name__ == '__main__':
app.run()
#输出:
* Serving Flask app "flaskdemo" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Jan/2019 11:27:17] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Jan/2019 11:27:21] "GET /rabbit HTTP/1.1" 200 -
127.0.0.1 - - [28/Jan/2019 11:26:06] "GET /22222 HTTP/1.1" 200 -
省一张截图,跟WSGI结果一致,关于Running on http://127.0.0.1:5000/
,Flask默认的Server监听端口为5000。
但愿没有讲太多,说好不拓展的。其实flask使用的就是装饰器,早在函数章节我们已经详细分析过了。更多其它关于web框架的使用我们在此就不多说了,上述内容也只是为了对python的web服务端形成一个基础性逻辑的认识。
二、客户端
urllib、urllib2库为python标准库,用于进行url请求,然而在实际使用中,要面对各种编码问题,所以我们选择自称HTTP for Humans的第三方库requests进行入门学习。
请求url,无非是为了数据,或者说是便捷享受服务,具象一下无非就是api或者是爬虫等,我们本次以api为例。
话说,很多网站都是主动提供api的,如百度翻译、地图等服务,以及我们此次用到的站长工具,当然,服务也是付费的,合情合理,同时也表示支持!
但我们此次不用做商业用途,仅供练习,所以选择了站长工具的IP查询功能进行举例,自行尝试使用burp等抓包工具进行数据包捕获。重放次数过多的话应该会被封IP吧,反正cmd5会的,这完全是为了方便个人使用,懒得开浏览器~
import requests
import re
def ip_adr():
headers = {'user-agent': 'ceshi/0.0.1'}
print('本脚本为接口练习使用,\n请勿批量使用。\n退出请输入exit……')
while True:
try:
target_ip = input('请输入目标域名/IP:')
if target_ip=='exit':
break
r = requests.get('http://ip.tool.chinaz.com/{}'.format(target_ip),headers=headers)
find_adr = re.compile(r'<span class="Whwtdhalf w50-0">.*</span>')
find_ip = re.compile(r'<span class="Whwtdhalf w15-0">.*</span>')
res1=find_adr.findall(r.text)
res2=find_ip.findall(r.text)
adr=re.findall(r'>.*<',str(res1[1]))
adr=str(adr)[3:]
adr=str(adr)[:-3]
ip=re.findall(r'>.*<',str(res2[4]))
ip=str(ip)[3:]
ip=str(ip)[:-3]
print('目标IP为:{}\n物理地址为:{}'.format(ip,adr))
except:
print('您的格式有误,大侠请重新来过~')
if "__main__" == __name__ :
ip_adr()
#输出:
本脚本为接口练习使用,
请勿批量使用。
退出请输入exit……
请输入目标域名/IP:www
您的格式有误,大侠请重新来过~
请输入目标域名/IP:baidu.com
目标IP为:123.125.115.110
物理地址为:北京亦庄联通机房
请输入目标域名/IP:exit
Process finished with exit code 0
其中url请求由requests模块完成,数据捕获与处理由re模块进行正则匹配。
既然讲到了这里,我们就尝试一下综合以上所学,将我们的小脚本使用flask布在服务器上!
首先改写下我们的脚本,用于flask调用,命名为为IpWhere:
#IpWhere
import requests
import re
def ip_adr(target_ip):
headers = {'user-agent': 'ceshi/0.0.1'}
r = requests.get('http://ip.tool.chinaz.com/{}'.format(target_ip),headers=headers)
find_adr = re.compile(r'<span class="Whwtdhalf w50-0">.*</span>')
find_ip = re.compile(r'<span class="Whwtdhalf w15-0">.*</span>')
res1=find_adr.findall(r.text)
res2=find_ip.findall(r.text)
adr=re.findall(r'>.*<',str(res1[1]))
adr=str(adr)[3:]
adr=str(adr)[:-3]
ip=re.findall(r'>.*<',str(res2[4]))
ip=str(ip)[3:]
ip=str(ip)[:-3]
return '目标IP为:{}\n物理地址为:{}'.format(ip,adr)
if "__main__" == __name__ :
print(ip_adr('baidu.com'))
服务器端进行flask框架调用:
from flask import Flask
from flask import request
from IpWhere import ip_adr
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
return '''<div align="center">
<h1>欢迎来到IP查询系统</h1>
<h3>本系统为接口练习使用,请勿批量使用</h3>
<form action="/ip" method="get">
<p><button type="submit">IP查询系统</button></p>
</form>
</div>'''
@app.route('/ip', methods=['GET'])
def ip_form():
return '''<div align="center">
<form action="/ip" method="post">
<p><input name="target_ip"></p>
<p><button type="submit">查询</button></p>
</form>
</div>'''
@app.route('/ip', methods=['POST'])
def ipis():
try:
res=ip_adr(request.form['target_ip'])
return '<div align="center">{}</div>'.format(res)
except:
return '<div align="center">再乱输打屎你个瓜娃子!</div>'
if __name__ == '__main__':
app.run()
#输出:
* Serving Flask app "flaskip" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Jan/2019 21:14:43] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Jan/2019 21:14:48] "GET /ip? HTTP/1.1" 200 -
127.0.0.1 - - [28/Jan/2019 21:14:52] "GET /ip HTTP/1.1" 200 -
127.0.0.1 - - [28/Jan/2019 21:15:05] "POST /ip HTTP/1.1" 200 -
127.0.0.1 - - [28/Jan/2019 21:15:13] "POST /ip HTTP/1.1" 200 -
时间关系,没有进行界面优化,只是做了个简单的button,看下效果:
效果图丑是丑了点>,<,可是效果够啦~
关于数据处理这一块,如果是某些api返回json文件,可以通过调用json模块进行处理,如果是其它类型,大家可以像这样借助正则匹配或者借助bs4等第三方插件进行处理。
显然,web方面的应用会是之后的重点,作为基础入门,今天就到这里~
网友评论