搜索
您的当前位置:首页正文

搭建一个 802.1x 的 web 测试服务

来源:二三娱乐

前言

轮子

需求

先整理一下需求:

  • 我们需要一个 web 表单,让用户输入他的用户名和密码进行测试,并返
    回结果
  • 不同的 SSID 应该能生成对应不同的表单页面
  • 得加一个验证码来防止坏人猜密码
  • 最好再有个 API 可供程序调用,这样可以构建自动化的监控
  • API 得有访问控制

实现

├── app
│   ├── framd.ttf  #字体文件,用来生成验证码的
│   ├── __init__.py
│   ├── static # 静态文件,css,js 之类的
│   ├── templates # web 模板 
│   ├── utils.py 
│   └── views.py 
├── config.py # 配置文件
├── control # 启动脚本
├── gunicorn.conf # gunicorn 的配置文件
├── lib # radius 报文的封装 lib(就是我们找的那个轮子)
│   ├── bidict.py
│   ├── client.py
│   ├── dictfile.py
│   ├── dictionary.py
│   ├── dicts
│   ├── host.py
│   ├── __init__.py
│   ├── mschap2.py
│   ├── packet.py
│   └── tools.py
├── LICENSE
├── README-CN.md
├── README.md
├── requirement.txt
├── run.py
└── var
    └── app.log

先从 config.py 说起,我们的配置都放在这儿


# BASIC APP CONFIG
BIND_ADDRESS = '0.0.0.0'
PORT = 81
SECRET_KEY = "session_secret_key"  # 建立 session 所使用的 key,session 用来存验证码

# SSID CONFIG
SSID_CONFIG = {
        "test1x":
            {"RADIUS_HOST":"192.168.0.210","RADIUS_SECRET":"802.1x","RADIUS_PORT":1812,"NAS_IP":"192.168.80.5"},
        "eduroam":
            {"RADIUS_HOST":"192.168.0.220","RADIUS_SECRET":"eduroam","RADIUS_PORT":1812,"NAS_IP":"192.168.80.5"},
        }
# 字典的 key 将作为 url 的路径,例如 

# API_KEY
API_KEY = "0c8d964e8fbd4cfcd040b5691d119968"

挑战报文

def radius_challenge(username, password, host, secret, port, nasip, debug):
        hostname = gethostname()
        dict_path = sys.path[0] + "/lib/dicts/dictionary"
        radius = Client(server = host, secret = secret, authport = port, dict = Dictionary(dict_path))
        request = radius.CreateAuthPacket(code = packet.AccessRequest)
        if debug:
                print "[DEBUG] assembling packet attributes"
        request["User-Name"] = username
        request["NAS-IP-Address"] = nasip
        request["NAS-Identifier"] = hostname
        ……
        ……

我们把轮子里的代码重新封装一下,构造一个函数出来负责发送 Radius 挑战报文。后面就用调用它来做 Radius 的测试

验证码

由于我们提供的是一个开放的测试表单,因此必须要有验证码,否则坏人就要暴力猜密码叻。我们使用 PIL 库进行验证码图像的生成,并把验证码图像对应的数字存在 session 里面。

@app.route('/code', methods=['GET'])
def code():
    """生成验证码
    """
    from io import BytesIO

    output = BytesIO()
    code_img, code_str = create_validate_code() # 生成验证码的函数,在 utils.py 里
    code_img.save(output, 'jpeg')
    img_data=output.getvalue()
    output.close()
    response = make_response(img_data)
    response.headers['Content-Type'] = 'image/jpg'
    session['code_text'] = code_str # 把正确的验证码数字放进 session 里待校验
    return response

表单

@app.route('/test/<string:ssid>', methods=['GET','POST'])
def radius_test(ssid):
        ssid_config = app.config['SSID_CONFIG']
        if ssid not in ssid_config:
                return "404 page not found",404
        if request.method == 'GET':
                return render_template('radius1x.html',ssid=ssid)
        ……
        ……

根据配置不同的 SSID 生成不同的表单 URL,通过校验 session 中的验证码来判断验证码是否正确。然后将收到的用户名和密码发送给 Radius 做测试

API

@app.route('/api/v1/<string:ssid>', methods=['POST'])
def radius1x_api(ssid):
    ssid_config = app.config['SSID_CONFIG']
    if ssid not in ssid_config:
        return "404 page not found",404
        ……
        ……

提供 API 的接口,供程序来调用,通过配置文件中的 API_KEY 进行鉴权

部署

#!/bin/bash

WORKSPACE=$(cd $(dirname $0)/; pwd)
cd $WORKSPACE

mkdir -p var

module=1xtest
app=radius-$module
pidfile=var/app.pid
logfile=var/app.log

function check_pid() {
    if [ -f $pidfile ];then
        pid=`cat $pidfile`
        if [ -n $pid ]; then
            running=`ps -p $pid|grep -v "PID TTY" |wc -l`
            return $running
        fi
    fi
    return 0
}

function start() {
    source env/bin/activate
    hash gunicorn 2>&- || { echo >&2 "I require gunicorn but it's not installed.  Aborting."; exit 1; }

    check_pid
    running=$?
    if [ $running -gt 0 ];then
        echo -n "$app now is running already, pid="
        cat $pidfile
        return 1
    fi

    gunicorn -c gunicorn.conf run:app -D -t 6000 --pid $pidfile --error-logfile $logfile --log-level info
    sleep 1
    echo -n "$app started..., pid="
    cat $pidfile
}
……
……

这样就可以使用 ./control start,./control stop 来进行服务启停了。

运行截图

image.png
[root@host ~]# curl -H "Content-Type: application/json" -d  
{
  "result": {
    "method": "mschapv2", 
    "success": true, 
    "time": 0.36426687240600586, 
    "username": 
  }
}

联盟监控

以上

转载授权

Top