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

相关文章

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四: