Pam-Python实现SSH的短信双因素认证

2023-12-29 07:08

本文主要是介绍Pam-Python实现SSH的短信双因素认证,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

谈及到双因子认证或多因子认证时,解决方案有很多,可能会想到短信验证码、RSA动态令牌、Google Authenticator或者Duo,在国内由于某些限制的原因,Google Authenticator和Duo的应用案例较少,而RSA动态令牌主要常见于一些大公司里面,而且使用RSA动态令牌需要独立独立部署RSA 服务器,并且软件需要收费,RSA SecurID密保也是要收费的,如何实现一种经济实惠的双因素认证呢?这里介绍利用python的pam_python模块实现SSH的短信双因素认证。

首先需要简单了解一下Linux中的PAM模块。PAM(PluggableAuthentication Module,可插拔认证模块)机制,采用模块化设计和插件功能,使用户可以轻易地在应用程序中插入新的认证模块或替换原先的组件,同时不必对应用程序做任何修改。详细的PAM介绍可参考:http://www.infoq.com/cn/articles/linux-pam-one 。Pam_python是一款开源的python模块,它将需要使用C语言编写的PAM模块转换成了可以使用python语言编写。

接下来就介绍如何利用pam_python模块实现SSH的短信双因素认证。首先需要编译和安装pam_python模块。依次执行以下命令:

yum install pampam-devel -y   #安装编译需要的依赖wget -Opam-python_1.0.6.tar.gz https://sourceforge.net/projects/pam-python/files/latest/download?source=files --no-check-certificate   #下载pam_python模块tar xvfpam-python_1.0.6.tar.gzcd pam-python_1.0.6make libcp  src/build/lib.linux-x86_64-2.7/pam_python.so/lib64/security/.
接下来就是编写python脚本实现SSH登陆的短信双因素认证。既然是短信双因素认证,就需要一个短信接口用来发送短信。

 image.png

生成随机验证码并调用短信发送接口发送给用户手机号码。

 image.png

最后是SSH登陆与用户交互过程并校验验证码的准确性。

 image.png

完整代码内容如下:

# -*- coding: utf-8 -*-import random, string, hashlib, requestsimport urllib,urllib2import pwd, syslogclass SMSOperation:"""短信发送接口"""def__init__(self, pin, phone_num):self.pin = pinself.phone_num = phone_numself.url = "短信服务地址"self.params = {"account":"短信服务用户名","pswd":"短信服务密码","msg":"One Time Pin:"+str(pin),"mobile":str(phone_num),"needstatus":"false","extno":""}defparse_number(self):"""设置用户手机号参数"""try:self.params['mobile'] =self.phone_numreturn 1except:auth_log("Invalidphone number %s. Please check." % (user))defsend_text(self,pamh):"""发送请求"""try:self.parse_number()except:auth_log("Invalidphone number %s. Please check." % (user))#msg = pamh.Message(pamh.PAM_ERROR_MSG,"The params are : (%s)"% (self.params))#pamh.conversation(msg)resp = requests.post(self.url, data=self.params)temp =resp.content.split(',')[1]if(temp!=0):auth_log("Message cannot be sentto (%s), please check." %(self.phone_num) )def auth_log(msg):"""保存日志到/var/log/messages"""syslog.openlog(facility=syslog.LOG_AUTH)syslog.syslog("MultiFactors Authentication: " + msg)syslog.closelog()def get_hash(plain_text):"""获取短信验证码的sha512字符串,与用户输入的验证码进行校验"""key_hash = hashlib.sha512()key_hash.update(plain_text)return key_hash.digest()def get_user_number(user):"""获取用户手机号码"""try:comments = pwd.getpwnam(user).pw_gecosexcept:auth_log("No local user (%s) found." % user)return -1try:return comments.split(',')[2] # 返回用户手机号except:auth_log("Invalid comment block for user %s. Phone number must belisted as Office Phone" % (user))return -1def gen_key(pamh, user, user_number, length):"""生成短信验证码并发送到用户手机"""pin= ''.join(random.choice(string.digits) for i in range(length))msg= pamh.Message(pamh.PAM_ERROR_MSG, "The pin is: (%s)" % (pin)) # 登陆界面输出验证码,测试目的,实际使用中注释掉即可pamh.conversation(msg)sms= SMSOperation(pin, user_number)try:sms.send_text(pamh)except:if not user_number:auth_log("No phonenumber listed for user (%s)." % (user))else:auth_log("Errorsending PIN to the given SMS number. (%s)" % (user_number))return -1return get_hash(pin)def pam_sm_authenticate(pamh, flags, argv):PIN_LENGTH = 6 # 短信验证码长度try:user = pamh.get_user()user_number = get_user_number(user)except pamh.exception, e:return e.pam_resultifuser is None or user_number == -1:msg = pamh.Message(pamh.PAM_ERROR_MSG,"[1]Unable to get user's phone number.\nPlease check.")pamh.conversation(msg)return pamh.PAM_ABORTpin= gen_key(pamh, user, user_number, PIN_LENGTH)ifpin == -1:msg = pamh.Message(pamh.PAM_ERROR_MSG, "[2]One time PIN could notbe generated.\nPlease check (%s)" % (user_number))pamh.conversation(msg)return pamh.PAM_ABORTforattempt in range(0,3): # 仅允许三次错误尝试msg = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "Enter one time PIN:")resp = pamh.conversation(msg)if get_hash(resp.resp) == pin: #用户输入与生成的验证码进行校验return pamh.PAM_SUCCESSelse:continuereturn pamh.PAM_AUTH_ERRdef pam_sm_setcred(pamh, flags, argv):return pamh.PAM_SUCCESSdef pam_sm_acct_mgmt(pamh, flags, argv):return pamh.PAM_SUCCESSdef pam_sm_open_session(pamh, flags, argv):return pamh.PAM_SUCCESSdef pam_sm_close_session(pamh, flags, argv):return pamh.PAM_SUCCESSdef pam_sm_chauthtok(pamh, flags, argv):return pamh.PAM_SUCCESS

保存脚本文件到/lib64/security/目录下,这里将脚本命名为:Multiauth.py。

接下来是配置SSHD,启用PAM的短信认证模块。

 vi /etc/pam.d/sshd 添加一行内容如下:

 

       auth      requisite    pam_python.so   Multiauth.py

 

image.png

同时需要启用ChallengeResponseAuthentication,修改/etc/ssh/sshd_config,将ChallengeResponseAuthentication设置为yes即可。

image.png

在上面的代码里面,获取用户手机号码的时候使用的方法是:pwd.getpwnam(user).pw_gecos,这里我将用户的手机号码信息存放在/etc/passwd文件中,当然可以根据需要存放在其他地方,这里只是用作演示。

 image.png

一切配置完成之后,需要重启ssh服务:systemctl restart sshd.service

重启完成之后,使用gary账号ssh登陆目标主机时,就启用了短信双因素认证了。

image.png

如果在运行过程中发生错误,异常日志信息记录在/var/log/secure文件中,正常的运行日志记录在/var/log/messages中。

这里简单介绍了如何利用pam_python模块实现ssh登陆的短信验证码双因素认证,在实际的安全场景中,实现业务主机的双因素安全认证,可根据实际的安全需求进行调整,例如针对不同用户开启短信验证码,用户手机号码的存储,短信验证码的发送频率限制,短信接口访问的限制。

更多Python视频、源码、资料加群683380553免费获取

*本文作者:yuegui_2004,转载请注明FreeBuf.COM

这篇关于Pam-Python实现SSH的短信双因素认证的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/548719

相关文章

Redis分片集群的实现

《Redis分片集群的实现》Redis分片集群是一种将Redis数据库分散到多个节点上的方式,以提供更高的性能和可伸缩性,本文主要介绍了Redis分片集群的实现,具有一定的参考价值,感兴趣的可以了解一... 目录1. Redis Cluster的核心概念哈希槽(Hash Slots)主从复制与故障转移2.

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

基于Python打造一个可视化FTP服务器

《基于Python打造一个可视化FTP服务器》在日常办公和团队协作中,文件共享是一个不可或缺的需求,所以本文将使用Python+Tkinter+pyftpdlib开发一款可视化FTP服务器,有需要的小... 目录1. 概述2. 功能介绍3. 如何使用4. 代码解析5. 运行效果6.相关源码7. 总结与展望1

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Docker镜像修改hosts及dockerfile修改hosts文件的实现方式

《Docker镜像修改hosts及dockerfile修改hosts文件的实现方式》:本文主要介绍Docker镜像修改hosts及dockerfile修改hosts文件的实现方式,具有很好的参考价... 目录docker镜像修改hosts及dockerfile修改hosts文件准备 dockerfile 文

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown