Python入门系列

Python入门系列(十一)——WEB

2019-01-28  本文已影响221人  RabbitMask

在渗透行业提及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方面的应用会是之后的重点,作为基础入门,今天就到这里~

上一篇 下一篇

猜你喜欢

热点阅读