使用otp动态口令ssh登录linux

本文介绍了如何在Linux上通过PAM机制和pam_script模块结合OTP动态口令实现SSH登录验证。步骤包括安装pam_script、修改sshd配置、创建认证脚本以及使用Python脚本验证OTP口令。
Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

linux上各应用的权限认证使用pam机制(http://www.linux-pam.org/ https://github.com/linux-pam/linux-pam )。

这里需要一个支持otp验证的pam模块,可以直接用pam_script模块,通过编写脚本实现。

1. 安装pam_script

yum install pam_script或从https://github.com/jeroennijhof/pam_script编译安装。

这里直接yum安装,会安装下面几个文件:

[root@localhost root]# ll /lib64/security/pam_script.so 
-rwxr-xr-x. 1 root root 15416 8月  23 2016 /lib64/security/pam_script.so
[root@localhost root]# ll /etc/pam_script*
-rwxr-xr-x. 1 root root 3836 2月  13 12:21 /etc/pam_script
lrwxrwxrwx. 1 root root   10 2月  10 14:59 /etc/pam_script_acct -> pam_script
lrwxrwxrwx. 1 root root   10 2月  10 14:59 /etc/pam_script_auth -> pam_script
lrwxrwxrwx. 1 root root   10 2月  10 14:59 /etc/pam_script_passwd -> pam_script
lrwxrwxrwx. 1 root root   10 2月  10 14:59 /etc/pam_script_ses_close -> pam_script
lrwxrwxrwx. 1 root root   10 2月  10 14:59 /etc/pam_script_ses_open -> pam_script

另外还会生成/etc/pam-script.d/目录。

2. 修改/etc/pam.d/sshd文件,最前面增加下面一行配置,表示使用pam_script认证,只要通过pam_script认证成功就通过,否则,则使用原来的方式验证。

auth    sufficient            pam_script.so

3. 参考pam_script的资料和源码可知,使用pam_script进行认证,会调用/etc/pam_script_auth,实际调用的是/etc/pam_script,进一步调用/etc/pam-script.d/*_auth。

/etc/pam-script.d/*_auth里能得到请求认证的用户名密码等,exit的值为1即为认证失败。

所以只需要在/etc/pam-script.d/下增加一个*_auth的文件,能以otp方式判断用户名密码是否正确,相应返回exit值即可。

文件:/etc/pam-script.d/totp_auth

#! /bin/sh

stamp=`/bin/date +'%Y-%m-%d %H:%M:%S'`
script=`basename $0`
LOGFILE=/tmp/pam-script.log
echo ============= >> $LOGFILE
echo $stamp $script $PAM_SERVICE $PAM_TYPE                              \
        user=$PAM_USER ruser=$PAM_RUSER rhost=$PAM_RHOST                \
        tty=$PAM_TTY                                                    \
        args=["$@"]                                                     \
        >> $LOGFILE

echo check $PAM_USER >> $LOGFILE

#if [[ "x$PAM_AUTHTOK" == "123456" ]]; then
#       exit 0
#fi
#exit 1

python3 /root/check_totp.py $PAM_USER $PAM_AUTHTOK
exit $?

 这里进一步使用python脚本检查otp动态口令是否正确。

totp密钥配置在认证用户的个人目录下的.pam_totp.conf中,以一行一组k=v格式配置key、key_format、window、interval参数,文件所有者需要为认证用户,读写权限为0600。

文件:/root/check_totp.py

# -*- coding: utf-8 -*-
import time
import os,sys
import pwd,stat
from otp import *

# 日志
def logprint(*msg):
    pass
    #print(*msg)

# 读取配置,格式每行一组k=v
def get_config(path):
    logprint('load config: ', path)
    config = {}
    with open(path, 'r') as f:
        while True:
            line = f.readline()
            if not line:
                break
            if line.startswith('#'):
                continue
            idx = line.find("=")
            if idx >= 0:
                a = line[0:idx]
                b = line[idx+1:]
                config[a.strip()] = b.strip()
    logprint('config: ', config)
    return config

# 检查totp口令
def check(username, token):
    if not username or not token:
        return 1

    #### 获取用户
    uu = pwd.getpwnam(username)
    if not uu:
        logprint('用户没找到')
        return 1

    #### 获取路径
    if not uu.pw_dir:
        logprint('用户目录没找到')
        return 1
    path = uu.pw_dir + '/.pam_totp.conf'

    ### 获取totp配置文件信息,要求文件权限为0600,文件所属为当前认证用户
    fst = os.stat(path)
    mode = fst.st_mode

    if not stat.S_ISREG(mode):
        logprint('totp配置文件不是普通文件')
        return 1

    if fst.st_size <= 0 or fst.st_size > 1024 * 10:
        logprint('totp配置文件为空或文件大小超过10KB')
        return 1

    if stat.S_IMODE(mode) != (0o600):
        logprint('totp配置文件权限不是0600')
        return 1

    uid = fst.st_uid
    if fst.st_uid != uu.pw_uid:
        logprint('totp配置文件所有者不是当前认证用户')
        return 1

    #### 获取配置
    config = get_config(path)
    key = config.get('key')
    key_format = config.get('key_format')
    window = config.get('window')
    interval = config.get('interval')

    if not key:
        logprint('otp参数项key为空')
        return 1
    if not key_format:
        key_format = "string"
    if not window:
        window = 3
    if not interval:
        interval = 30

    #### 验证totp
    t = TOTP(None, int(window), int(interval))
    t.setSecret(key, key_format)

    if t.verify(token) != True:
        logprint('totp检测失败')
        return 1
    else:
        logprint('totp检查成功')
        return 0

def main(argv):
    #time.sleep(3)
    if len(argv) < 3:
        logprint('参数个数错误')
        exit(1)
    username = argv[1]
    token = argv[2]
    ret = check(username, token)
    logprint('检测结果:', ret)
    exit(ret)

if __name__ == "__main__":
    main(sys.argv)

文件:/root/otp.py

# 参看https://gitee.com/superzlc/otp

文件:.pam_totp.conf

key=202102191234567890qwertyuiop
key_format=string
window=3
interval=30

4. 其他

totp动态口令,可以用微信小程序“动态口令”生成。

 

 

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值