标签 wifidog服务器 下的文章

编写自己的WifiDog认证服务器

这次我使用的是php来编写auth_server服务器,因为这样比较简单。
1.首先是login.php

<?php  
include './tool/MySQLHelper.php';  
if (!empty($_GET["mac"])){  
    $result = selectMacByToken($_GET["mac"]);  
    if (!empty($result)){  
        header("location: http://192.168.1.1:2060/wifidog/auth?token=".$result);  
    }  
    else {  
        header("location: http://xxxxx/WelcomePage.php?mac=".$_GET["mac"]);  
    }  
}  
else {  
    header("location: http://xxxxx/WelcomePage.php?mac=".$_GET["mac"]);  
}  
?>  

2.ping.php

<?php  
echo "Pong";  
?>  

这里没有做额外的处理,只是简单地向wifidog回应一个Pong。
3.auth.php

<?php  
// 后门  
if ($_GET["token"] == "123"){  
    echo "Auth: 1";  
    return;  
}  

if (!empty($_GET["token"]) && isset($_GET["token"])){  
    //获取$result的过程//  
    isValidate($result);  
    //**后续处理**//  
    return;  
}  
else if((!empty ($_GET["mac"])) && isset($_GET["mac"])){  
    //**获取result*//  
    $result = isSubscribeByMac($_GET["mac"]);  
    isValidate($result);  
    return;  
}  
else  
{  
    echo "Auth: 0";  
}  

// 输出是否合法.  
function isValidate($result){  
    if ($result == 1){  
        echo "Auth: 1";  
    }  
    else {  
        echo "Auth: 0";  
    }  
}  
?>  

这里根据一些参数来获取$result,从而决定是否允许认证。
4.welcomePage.php以及Portal.html就不一一列举了。

本文章由 http://www.wifidog.pro/2015/06/08/wifidog%E8%AE%A4%E8%AF%81%E6%9C%8D%E5%8A%A1%E5%99%A8-4.html 整理编辑,转载请注明出处

wifidog用php实现验证流程

步骤
1.首先简单说说wifidog认证的过程
客户端首次连接到wifi后,浏览器请求将会被重定向到:

login/?gw_address=%s&gw_port=%d&gw_id=%s&url=%s

验证通过后,客户端被重定向到网关,url格式如下:
http://网关地址:网关端口/wifidog/auth?token=
wifidong会启动一个线程周期性地报告每一个用户的状态信息,并通过如下地址发送给认证
服务器:

auth_server:/auth/?stage=
ip=
mac=
token=
incoming=
outgoing=

认证服务器根据该状态信息决定是否允许该用户继续连接,并回复网关,回复格式为:Auth:状态码,
如:Auth:1
常用状态码:
0:AUTH_DENIED,表示拒绝
1:AUTH_ALLOWED,验证通过
验证通过后,将重定向到如下地址:
portal/?gw_id=%s
wifidog的ping协议
wifidog通过ping协议将当前状态信息发送给认证服务器,发送地址为:

http://auth_sever/ping/?
gw_id=%s
sys_uptime=%lu
sys_memfree=%u
sys_load=%.2f
wifidog_uptime=%lu

认证服务器须返回一个“Pong”作为回应。
具体php实现代码如下

public function auth()
    {
        //响应客户端的定时认证,可在此处做各种统计、计费等等
        /*
            wifidog 会通过这个接口传递连接客户端的信息,然后根据返回,对客户端做开通、断开等处理,具体返回值可以看wifidog的文档
        wifidog主要提交如下参数
        1.ip
        2. mac
        3. token(login页面下发的token)
        4.incoming 下载流量
        5.outgoing 上传流量
        6.stage  认证阶段,就两种 login 和 counters
        */


        $stage = $_GET['stage'] == 'counters'?'counters':'login';
        if($stage == 'login')
        {
            //XXXX跳过login 阶段的处理XXXX不能随便跳过的
            //默认返回 允许
            echo "Auth: 1";
        }
        else if($stage == 'counters')
        {

            //做一个简单的流量判断验证,下载流量超值时,返回下线通知,否则保持在线
            if(!empty($_GET['incoming']) and $_GET['incoming'] > 10000000)
            {
                echo "Auth: 0";
            }else{
                echo "Auth: 1\n";
            }
        }
        else
            echo "Auth: 0"; //其他情况都返回拒绝


        /*
            返回值:主要有这两种就够了
        0 - 拒绝
        1 - 放行

        官方文档如下
        0 - AUTH_DENIED - User firewall users are deleted and the user removed.
        6 - AUTH_VALIDATION_FAILED - User email validation timeout has occured and user/firewall is deleted(用户邮件验证超时,防火墙关闭该用户)
        1 - AUTH_ALLOWED - User was valid, add firewall rules if not present
        5 - AUTH_VALIDATION - Permit user access to email to get validation email under default rules (用户邮件验证时,向用户开放email)
        -1 - AUTH_ERROR - An error occurred during the validation process
        */
    }
    public function portal()
    {
        /*
         wifidog 带过来的参数 如下
        1. gw_id
        */
        //重定到指定网站 或者 显示splash广告页面
        redirect('http://www.baidu.com', 'location', 302);

    }
    public function ping()
    {
        //url请求 "gw_id=$gw_id&sys_uptime=$sys_uptime&sys_memfree=$sys_memfree&sys_load=$sys_load&wifidog_uptime=$wifidog_uptime";
        //log_message($this->config->item('MY_log_threshold'), __CLASS__.':'.__FUNCTION__.':'.debug_printarray($_GET));

        //判断各种参数是否为空
        if( !(isset($_GET['gw_id']) and isset($_GET['sys_uptime']) and isset($_GET['sys_memfree']) and isset($_GET['sys_load']) and isset($_GET['wifidog_uptime']) ) )
        {
            echo '{"error":"2"}';
            return;
        }
        //添加心跳日志处理功能
        /*
            此处可获取 wififog提供的 如下参数
        1.gw_id  来自wifidog 配置文件中,用来区分不同的路由设备
        2.sys_uptime 路由器的系统启动时间
        3.sys_memfree 系统内存使用百分比
        4.wifidog_uptime wifidog持续运行时间(这个数据经常会有问题)
        */

        //返回值
        echo 'Pong';
    }
    /**
     * wifidog 的gw_message 接口,信息提示页面
     */
    function gw_message()
    {
        if (isset($_REQUEST["message"])) {
            switch ($_REQUEST["message"]) {
                case 'failed_validation':
                    //auth的stage为login时,被服务器返回AUTH_VALIDATION_FAILED时,来到该处处理
                    //认证失败,请重新认证
                    break;
                case 'denied':
                    //auth的stage为login时,被服务器返回AUTH_DENIED时,来到该处处理
                    //认证被拒
                    break;
                case 'activate':
                    //auth的stage为login时,被服务器返回AUTH_VALIDATION时,来到该处处理
                    //待激活
                    break;
                default:
                    break;
            }
        }else{
            //不回显任何信息
        }
    }

本文章由 http://www.wifidog.pro/2015/04/09/wifidog-php-2.html 整理编辑,转载请注明出处

wifidog认证wifidog流程auth server简单配置

前段时间使用wifidog进行wifi强制认证,现在做个小结。
1.首先简单说说wifidog认证的过程
客户端首次连接到wifi后,浏览器请求将会被重定向到:

login/?gw_address=%s&gw_port=%d&gw_id=%s&url=%s

验证通过后,客户端被重定向到网关,url格式如下:
http://网关地址:网关端口/wifidog/auth?token=
wifidong会启动一个线程周期性地报告每一个用户的状态信息,并通过如下地址发送给认证
服务器:

auth_server:/auth/?stage=
ip=
mac=
token=
incoming=
outgoing=

认证服务器根据该状态信息决定是否允许该用户继续连接,并回复网关,回复格式为:Auth:状态码,
如:Auth:1
常用状态码:
0:AUTH_DENIED,表示拒绝
1:AUTH_ALLOWED,验证通过
验证通过后,将重定向到如下地址:
portal/?gw_id=%s
wifidog的ping协议
wifidog通过ping协议将当前状态信息发送给认证服务器,发送地址为:

http://auth_sever/ping/?
gw_id=%s
sys_uptime=%lu
sys_memfree=%u
sys_load=%.2f
wifidog_uptime=%lu

认证服务器须返回一个“Pong”作为回应。
2.实战应用
struts配置文件:

<package name="index" namespace="/" extends="interceptorMy,struts-default">
<action name="login/" class="goodsAction" method="login">
<result name="success" type="redirect">/Login/index.jsp</result>
<result name="input">/error.jsp</result>
</action>
<action name="ping/" class="goodsAction" method="ping">
</action>
 <action name="auth/" class="goodsAction" method="auth">
</action>
<action name="portal/" class="goodsAction" method="portal">
</action>
</package>

Action方法

public String login() {
    try{
        System.out.println("login start!");
                System.out.println("gw_port:"+gw_port);
        System.out.println("login end!");

     }
    catch(Exception e)
    {
        e.printStackTrace();
        return INPUT;
    }
    return "success";
}
public void ping() {
    try{
        System.out.println("ping start!");
        System.out.println(gw_id);
        ServletActionContext.getResponse().getWriter().write("Pong");
        System.out.println("ping end!");
         }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}
public void portal() {
    try{
        System.out.println("portal start");
        System.out.println("protal"+token);
    ServletActionContext.getResponse().sendRedirect("/demo/listAction");
        System.out.println("portal end");
     }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}
public void auth() {
    try{
        System.out.println("auth start!");
        System.out.println("mac"+mac);
        System.out.println("stage"+stage);
        System.out.println("token"+token);
        ServletActionContext.getResponse().getWriter().write("Auth: 1");
        System.out.println("auth end!");

     }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

/Login/index.jsp代码:

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    DateFormat format=new SimpleDateFormat("yyMMddHHmmss");
    String formatData=format.format(new Date());
    int ramdom=new Random().nextInt(1000);
    String token=formatData+ramdom;
    if(session.getAttribute("token")==null)
       session.setAttribute("token",token);

%>
<form method="GET" action='http://192.168.1.1:2060/wifidog/auth'>
<input type='hidden' name='token' value="<s:property value="#session.token" />" />
<input type='submit' value='Welcome!'/>
</form>

上面的192.168.1.1为网关的ip,2060为网关端口。
当然,完全可以在处理完login后直接跳到该地址。我们这里为演示其认证流程,故跳到该页面
效果:
客户端连接到wifi后,打开任何连接均跳到上面的index.jsp中,点击"Welcome"后,跳到/demo/listAction,即我们的目标地址。此后点击其他连接将不再拦截。
提示:安装wifidog的路由器必须可以访问Internet,否则wifidog拦截失败,无法跳到我们设定的页面。

本文章由 http://www.wifidog.pro/2015/04/08/wifidog%E6%B5%81%E7%A8%8Bwifidog%E8%AE%A4%E8%AF%81.html 整理编辑,转载请注明出处

wifidog分析-Radius协议

从事Radius协议开发有段时间了,小弟不怕才疏学浅,卖弄一下,从RADIUS协议谈谈对身份认证的认识,也总结一下自己。

一.RADIUS协议原理

    RADIUS(Remote Authentication Dial In User Service) 用户远程拨入认证服务,它主要针对的远程登录类型有:SLIP、PPP、telnet和rlogin等。RADIUS协议应用范围很广,包括普通电话、上网业务计费,对VPN的支持可以使不同的拨入服务器的用户具有不同权限。

RADIUS典型应用环境如下:
clip_image002.jpg

RADIUS数据包分为5个部分:
(1) Code:1个字节,用于区分RADIUS包的类型:常用类型有:
接入请求(Access-Request),Code=1;接入允许(Access-Accept),Code=2;接入拒绝(Access-Reject),Code=3;计费请求(Accounting-Request),Code=4等。
(2)Identifier:一个字节,用于请求和应答包的匹配。
(3)Length:两个字节,表示RADIUS数据区(包括Code, Identifier, Length, Authenticator, Attributes)的长度,单位是字节,最小为20,最大为4096。
(4)Authenticator:16个字节,用于验证服务器端的应答,另外还用于用户口令的加密。RADIUS服务器和NAS的共享密钥(Shared Secret)与请求认证码(Request Authenticator)和应答认证码(Response Authenticator),共同支持发、收报文的完整性和认证。另外,用户密码不能在NAS和RADIUS 服务器之间用明文传输,而一般使用共享密钥(Shared Secret)和认证码(Authenticator)通过MD5加密算法进行加密隐藏。
(5)Attributes:不定长度,最小可为0个字节,描述RADIUS协议的属性,如用户名、口令、IP地址等信息都是存放在本数据段。
各个属性的详细编码信息,以及数据格式,限于篇幅,这里不作具体介绍,感兴趣的,可以参看RFC文档,或与我交流。

二.RADIUS协议实现

目前,开源软件包freeRadius , tinyRadius,可以下载到其实现的源码。freeRadius是目前功能最强大的开源RADIUS 服务器软件,采用C语言实现,采用了多进程,进程池的处理方法,拥有很好的吞吐处理能力,同时,提供了连接各种数据库的应用接口,方便用户根据自己的需要进行适当的扩展。值得一提的是,它采用模块化处理,用户可以定做适合自己的认证计费处理模块。
freeRadius的功能强大,也造成了它模块的庞大,不易维护,对安装环境有一些要求。tinyRadius采用Java开发,短小精悍,能接收各种标准协议中的数据包,可以快速的完成对RADIUS数据包的封装与解包,我们可以自己的需要进行某些处理,具有很大的自由度,唯一的缺陷是单线程,没有数据库接口。

三.RADIUS协议对安全的考虑

RADIUS采用UDP协议基于以下几点原因:
1. NAS和RADIUS服务器大多在同一个局域网中,使用UDP更加快捷方便。
2. 简化了服务端的实现。
事实证明,采用UDP协议可行,RADIUS有自己的机制,来解决UDP丢包特点。
如果NAS向某个RADIUS服务器提交请求没有收到返回信息,那么可以要求备份RADIUS服务器重传。由于有多个备份RADIUS服务器,因此NAS进行重传的时候,可以采用轮询的方法。如果备份RADIUS服务器的密钥和以前RADIUS服务器的密钥不同,则需要重新进行认证。
下面重点从RADIUS协议来谈下它在身份认证中如何确保安全认证的。
1. Authenticator:鉴别码,分为请求鉴别码,回应鉴别码。
在“Access-Request”数据包中,Authenticator是一个16字节的随机数,称为“Request Authenticator”。 在机密的整个生存周期中(如RADIUAS服务器和客户端共享的机密),这个值应该是不可预测的,并且是唯一的,因为具有相同密码的重复请求值,使黑客有机会用已截取的响应回复用户。因为同一机密可以被用在不同地理区域中的服务器的验证中,所以请求认证域应该具有全球和临时唯一性。
为防止数据包中数据被截获被篡改,回应鉴别码采用如下方式生成:
ResponseAuth = MD5(Code+ID+Length+RequestAuth+ Attributes+Secret);
回应鉴别码是对整个数据包进行MD5演算产生的16字节索引,防止伪造服务器的回应。
2.加密方式。PAP,CAHP,EAP以及Unix登录认证三种加密认证方式。最常用的是前两种,下面介绍下:
PAP加密,采用此加密方法时,密码存放在User-Password属性中。
User-Password加密方法:
1.在密码的末尾用nulls代替填补形成多个十六个字节的二进制数;
2.把密码按16个字节为一组划分为p1、p2等等;
b1=MD5(Secret + Authenticator) c(1) = p1 异或 b1
b2 = MD5(S + c(1)) c(2) = p2 异或b2
bi = MD5(S + c(i-1)) c (i) = pi 异或 bi
c(1)+c(2)+...+c (i)
在接收时,这个过程被反过来,由于采用异或方式贯穿在每16个字节之间,同样的算法再异或一次,然后配合MD5演算,从而生成原始的密码,尽管这种加密方式是可逆的,黑客截获到密文后,能通过一定的手段来破解出密码,但如果共享密钥未知的情况下,很难破解,也就只能采用蛮力破解方法。使用共享密钥应采用合适的长度,来防止破解,不应过短。

PAP加密方法使密码以密文的方式在网络中进行传输,使黑客仍有有机可乘的机会,但CHAP加密方法阻止了密码的传输。
CHAP加密,采用此加密方法时,密码存放在Chap-Password属性中。
这种加密方法的原则是不是密码在网络中进行传输,而只是传输一个索引值,从而增加了安全性,但这样做的代价是,RADIUS服务端必须要知道用户的密码,从而再现密码索引值来和发来的认证请求中的密码索引值比对。
Chap-Password加密方法:
Md5(chapId+password+chapChallenge);
chapId :可以是随机产生的一字节码;
chapChallenge :NAS生成一个随机挑战字(16个字节比较合适)
该字段有时缺失,读取Authenticator域作为挑战字。
3.共享密钥(Secret):共享密钥在密码加密以及数据包的鉴别码部分都参与了运算,即使RADIUS数据包被截获,但不知道共享密钥,很难破解用户的密码伪造数据。共享密钥应采用合适的长度,不应过短,宽大密码范围能有效提供对穷举搜寻攻击的防卫,随着密钥长度的增加,其破解花费的时间将大大增加。
4.为防止非法用户的重放攻击,造成服务器瘫痪。如果在一个很短的时间片段里,一个请求有相同的客户源IP地址、源UDP端口号和标识符,RADIUS服务器会认为这是上一个重复的请求,将直接丢弃,不做任何处理。

四.总结

Radius协议本身比较易掌握,在应用中,可以结合其自身的密码方式,实现满足企业需要的更高强度的强认证,比如结合各种令牌卡,手机短信等等。对协议进行开发,离不开各种抓包工具,像sniffer,tcpdump,ethereal等抓包工具的使用。
外部用户要访问某局域网络中计算机设备,其访问方式有多种,比如采用VPN拨号,Telnet等等。如用户Telnet登陆时,产生用户名和密码信息,而NAS服务器AAA配置中指定了采用RADIUS作为认证服务器,则将其封装成RADIUS请求数据包发送到RADIUS服务器进行身份认证,RADIUS服务器通过NAS和用户进行交流,以提示用户认证通过与否,以及是否需要Challenge身份认证。

其工作原理为:用户接入NAS (Net Access Server),NAS一般为路由器等设备,NAS向RADIUS服务器使用Access-Request数据包提交用户信息,包括用户名、密码等相关信息,其中用户密码是经过MD5加密的,双方使用共享密钥,这个密钥不经过网络传播;RADIUS服务器对用户名和密码的合法性进行检验,必要时可以提出一个Challenge,要求进一步对用户认证,也可以对NAS进行类似的认证;如果合法,给NAS返回Access-Accept数据包,允许用户进行下一步工作,否则返回Access-Reject数据包,拒绝用户访问;如果允许访问,NAS向RADIUS服务器提出计费请求Account-Require,RADIUS服务器响应Account-Accept,对用户的计费开始,同时用户可以进行自己的相关操作。
RADIUS还支持代理和漫游功能。简单地说,代理就是一台服务器,可以作为其他RADIUS服务器的代理,负责转发RADIUS认证和计费数据包。所谓漫游功能,就是代理的一个具体实现,这样可以让用户通过本来和其无关的RADIUS服务器进行认证。
RADIUS能够实现其功能依赖于它自身的数据包结构。RADIUS采用的是UDP传输协议,认证和计费监听端口一般分别为:1812,1813。
以太网上的RADIUS封装后的包结构如下:
以太帧头|IP包头|UDP包头|RADIUS数据包|以太网FCS

在这里我们关心的是红色RADIUS数据包部分。
RADIUS数据包的格式如下:
2.gif

本文章由 http://www.wifidog.pro/2015/03/27/wifidog%E5%88%86%E6%9E%90-2.html整理编辑,转载请注明出处