资讯专栏INFORMATION COLUMN

Laravel学习笔记之Two-Factor Authentication神器——Duo

hoohack / 2979人阅读

摘要:在登录后台时也是必须认证才行。使用这种总比粗暴的限制访问来保护安全要高效的多,一切都是为了自动化,为了提高生产率。总结本文主要学习使用这个神器来做,并学习了如何使用集成进程序中。我司最近需要一名伙伴一起共同航海去,有兴趣速来。

说明:本文主要研究利用Duo来实现双重认证,Two-Factor Authentication就是除了username-password这种登录认证之外,还使用第二层安全认证,引用官网What is Two-Factor Authentication?的一句话:

A second layer of security to your login, in addition to your password.

这里,就是使用Duo来实现二次安全认证,保护程序防止被恶意者登录。需要实现二次登录认证的场景还是很多的,如登录云服务器AWS或Aliyun时只是账号密码登录是远远不够,安全性较差,如果登录AWS的private key被别人知道了,那恶意者也会登录到你的AWS,那就麻烦了,代码岂不暴露了;还有公司内部的一些后台网站,如果只是username-password这种基本认证也远不够安全,如果被别人知道了账号密码登陆进去那就泄露了公司秘密了,限制IP登录也挺麻烦的,那岂不是除了公司外其他地方不能访问内部网站了,如果想在家访问一个业务的后台就麻烦了。

使用Duo来做多一层保护会更安全,Duo的Web Application Protection工作原理如图:

上图描述的主要内容就是除了输入基本的账号密码认证外,还得经过Duo的二次认证。如在我司在登录AWS云时,除了private key认证外,还得必须经过Duo安全认证才能安全登录AWS,Duo认证选择的方式是Mobile Push Notification,这样当有恶意者知道了个人的private key想要登录AWS,个人的手机就会收到Duo Push Notification,只有个人在手机上选择Approve才能登录,而且也知道了private key被盗取了赶紧换一个key做补救措施。在登录后台时也是必须Duo认证才行。实际上,Duo还能集成进Github上,这样登录Github时也必须经过Duo认证,就算被知道了账号密码也不会被登录个人的Github账号。

这里主要学习下如何利用Duo来Protect Web Application,这里假设Web程序是Laravel写的,看如何集成进Laravel中实现二次认证。假设由于业务需求,有一个后台Admin,并是username-password这种HTTP Basic Authentication的(很多时候username-password认证在公司内都是SSO{Single Sign On},多个系统只需要一套username-password,这个可以使用Atlassian Crowd来做,以后再聊这个Crowd)。

开发环境:Laravel5.3 + PHP7

Duo Account

进去Duo官网注册个账号先,Duo Pricing对个人使用不超过10个用户时是免费的,其余套餐的价格也很便宜。然后在手机端下载个Duo应用。最后使用Duo账号登录进后台,后台登录使用Push认证,这样Duo Mobile App就会收到Push Notification,选择Approve就会自动登录Duo 后台:

登录后台,创建一个Application获取keys,不同的Application有不同的keys,这样可以不同的Admin后台使用不同Application的keys,方便管理:

选择Web SDK,因为本文是学习使用Duo的SDK集成进Admin后台,来保护后台Admin程序:

这样就得到了名叫Web SDK的Application了,并得到了对应的Integration key,Secret key,API hostname这三个keys,后续集成SDK时需要这三个keys:

Two-Factor Authentication

把Duo SDK集成进Laravel中实际上就是多加一个Middleware,这里假设名为auth.duo,先做个中间件:

php artisan make:middleware DuoTwoFactorAuthentication

然后写上中间件代码,首先经过username-password第一层认证(这里假设是HTTP Basic Authentication),然后再是Duo Authentication第二层认证,最后认证通过再$next($request):

guest()) {
            // Basic authentication is not set.
            return response("Unauthorized.", Response::HTTP_UNAUTHORIZED);
        } elseif ($request->session()->get(TwoFactorAuthenticationController::SESSION_KEY) == Auth::guard($guard)->user()->getAuthIdentifier()) {
            return $next($request);
        } else {
            // Duo Authentication
            // Basic authentication is set, but the duo middleware is not set.
            return redirect()->guest("/2fa");
        }
    }
}

并在AppHttpKernel中加上auth.duo:

    protected $routeMiddleware = [
        "auth"       => IlluminateAuthMiddlewareAuthenticate::class,
        "auth.basic" => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class,
        "auth.crowd" => MiddlewareCrowdAuthentication::class,
        "auth.duo"   => MiddlewareDuoTwoFactorAuthentication::class,
        "bindings"   => IlluminateRoutingMiddlewareSubstituteBindings::class,
        "can"        => IlluminateAuthMiddlewareAuthorize::class,
        "guest"      => MiddlewareRedirectIfAuthenticated::class,
        "throttle"   => IlluminateRoutingMiddlewareThrottleRequests::class,
    ];

然后写上路由就行web.php,这里是使用auth.basicLaravel自带的HTTP Basic Authentication(使用Crowd SSO登录以后再聊):

//Route::group(["middleware" => "auth.crowd"], function () {
Route::group(["middleware" => "auth.basic"], function () {
    Route::get("/2fa", "TwoFactorAuthenticationController@get");
    Route::post("/2fa", "TwoFactorAuthenticationController@post");

    Route::group(["middleware" => "auth.duo"], function () {
        Route::get("/duo", function () {
            return "Duo Authentication";
        });
    });
    
    Route::get("/duo/users", function () {
        return view("users");
    });
    
    Route::get("/duo/accounts", function () {
        return view("accounts");
    });
    // and so on
});

这样Admin程序后台路由是http://sentry.app:8888/duo(假设本地配置的host是sentry.app:8888),但需要经过HTTP Basic Authentication这个第一层认证,HTTP Basic Authentication就是根据输入的username-password来查询users表中有没有对应的user,这里先在users表中造一个,使用Laravel自带的Auth Scaffold,然后使用Register功能往users表中插入一个user,这样也方便:

php artisan make:auth

然后输入http://sentry.app:8888/register往users表插入一个username: user@example.com,password: lx1036

根据官方文档Duo Web中说明,需要安装一个package:

composer require duosecurity/duo_php

然后加上控制器TwoFactorAuthenticationController,这里需要向session中写入$user_id,这里使用redis作为session驱动,记得修改.env中SESSION_DRIVER=redis:

php artisan make:controller TwoFactorAuthenticationController


 config("services.duo.host"),
            "sig_request" => Web::signRequest(
                config("services.duo.integration_key"),
                config("services.duo.secret_key"),
                config("services.duo.application_key"),
                Auth::user()->getAuthIdentifier()
            ),
            "post_action" => url("2fa"),
        ]);
    }

    public function post(Request $request)
    {
        $user_id = Web::verifyResponse(
            config("services.duo.integration_key"),
            config("services.duo.secret_key"),
            config("services.duo.application_key"),
            $request->input("sig_response")
        );

        if ($user_id == Auth::user()->getAuthIdentifier()) {
            $request->session()->put(self::SESSION_KEY, $user_id);

            return redirect()->intended("/duo");
        } else {
            abort(Response::HTTP_UNAUTHORIZED);
        }
    }
}


// config/services.php
    "duo" => [
        "host"            => env("DUO_HOST"),
        "integration_key" => env("DUO_IKEY"),
        "secret_key"      => env("DUO_SKEY"),
        "application_key" => env("DUO_AKEY"),
    ],

记得在.env文件中写入DUO_HOST,DUO_IKEY,DUO_SKEY这三个从Web SDK 这个Application中得到的keys,DUO_AKEY根据官方文档是个人生成的,这里选择Laravel的APP_KEY。

最后按照官方文档的格式,把view页面写上:

// resources/views/duo/2fa.blade.php
@extends("layouts.duo")

@section("content")
    

Two Factor Authentication

{{csrf_field()}}
@stop @section("js") @endsection // resources/views/layouts/duo.blade.php Duo: Two Factor Authentication
@yield("content")
@yield("js") // public/css/duo/duo.css #duo_iframe { width: 100%; min-width: 304px; max-width: 620px; height: 330px; } #duo { align-content: center; margin: auto; }

其中,Duo-Web-v2.min.js是duosecurity/duo_php这个package里就有的,拷贝过来就行。

然后输入路由http://sentry.app:8888/duo会弹出Basic Authentication Form,输入刚刚注册的user@example.com,lx1036实现第一层认证后,再根据中间件DuoTwoFactorAuthentication的return redirect()->guest("/2fa");逻辑就会跳转到/2fa页面实现第二层认证:

选择Send me a Push后,手机端Duo APP就会就会收到Push Notification了,当然前提是手机端Duo已经登录了。选择Approve后桌面端程序就自动跳转到路由http://sentry.app:8888/duo,这次走的中间件DuoTwoFactorAuthentication中逻辑是$request->session()->get(TwoFactorAuthenticationController::SESSION_KEY) == Auth::guard($guard)->user()->getAuthIdentifier(),这样程序就经过二次认证了,程序就进入登陆后的页面,这里只是简单显示Duo Authentication

It is working.

有了Duo这个神器,就很安全的实现二次认证了,这里是展示了如何使用Web SDK来保护Web Application,需要编码,还可以在Duo后台配置实现服务器登录的二次认证,这些就是配置下就行,不需要编码,当然Duo还有很多其他集成来实现二次保护。使用这种Modern Security Protection总比粗暴的限制IP访问来保护安全要高效的多,一切都是为了自动化,为了提高生产率。Duo已经在我司RightCapital长时间使用了,用起来还很顺手,值得推荐下。

总结:本文主要学习使用Duo这个神器来做Two Factor Authentication,并学习了如何使用Web SDK集成进Laravel程序中。以后遇到好的技术再分享下,到时见。

我司最近需要一名伙伴一起共同航海去,有兴趣速来Profile。

欢迎关注Laravel-China。

RightCapital招聘Laravel DevOps

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30498.html

相关文章

  • Laravel学习笔记Errors Tracking神器——Sentry

    摘要:中异常处理类主要包含两个方法和,其中就是主要用来向第三方发送异常报告,这里选择向这个神器发送异常报告,并使用通知开发人员。通过也能发现的执行流程。 说明:Laravel学习笔记之bootstrap源码解析中聊异常处理时提到过Sentry这个神器,并打算以后聊聊这款神器,本文主要就介绍这款Errors Tracking神器Sentry,Sentry官网有一句话个人觉得帅呆了: Stop ...

    xiguadada 评论0 收藏0
  • Laravel学习笔记函数处理(Function Handling)

    摘要:提供了一些函数处理操作的内置函数,主要有开发环境是调用回调函数,并把一个数组作为参数传进去作为回调函数的参数也是调用回调函数,区别是并没有要求把数组作为参数传进回调函数做参数。 说明:Laravel中经常使用PHP的Function Handling来设计代码,本文主要学习PHP的Function Handling特性,来提高写代码时的设计质量。PHP提供了一些函数处理操作的内置函数,...

    Rindia 评论0 收藏0
  • Laravel学习笔记Schema Builder 和 Migration System(上)

    摘要:看下两个方法的源码同样是使用了对象来添加命令和。 说明:本文主要学习Schema Builder和Migration System的使用及相关原理。传统上在设计database时需要写大量的SQL语句,但Laravel提供了Schema Builder这个神器使得在设计database时使用面向对象方法来做,不需要写一行SQL,并且还提供了另一个神器Migration System,可...

    nevermind 评论0 收藏0
  • Laravel学习笔记Filesystem-从Dropbox中下载文件到AWS S3

    摘要:说明本文主要讲述了的文件系统的小,逻辑不复杂,主要就是把上的一个文件下载到本地,和下载到中。写驱动由于没有驱动,需要自定义下在中写上名为的驱动同时在注册下该就行。执行命令后,显示上文件从上下载到上的文件该逻辑简单,但很好玩。 说明:本文主要讲述了Laravel的文件系统Filesystem的小Demo,逻辑不复杂,主要就是把Dropbox上的一个文件下载到本地local,和下载到AWS...

    tylin 评论0 收藏0
  • Laravel学习笔记bootstrap源码解析

    摘要:总结本文主要学习了启动时做的七步准备工作环境检测配置加载日志配置异常处理注册注册启动。 说明:Laravel在把Request通过管道Pipeline送入中间件Middleware和路由Router之前,还做了程序的启动Bootstrap工作,本文主要学习相关源码,看看Laravel启动程序做了哪些具体工作,并将个人的研究心得分享出来,希望对别人有所帮助。Laravel在入口index...

    xiaoxiaozi 评论0 收藏0

发表评论

0条评论

阅读需要支付1元查看
<