我正在寻找一种方法,让我的Python程序通过pam处理身份验证。我正在使用http://code.google.com/p/web2py/source/browse/gluon/contrib/pam.py进行身份验证,只要我的Python程序作为root运行,这个方法就非常好用,但我认为这并不理想。
如何在不需要root权限的情况下利用pam进行用户名/密码验证?
如何在不需要root权限的情况下利用pam进行用户名/密码验证?
简短: 使用适当的Python PAM实现,正确设置PAM。
详细: 在合理的PAM设置中,您不需要root
特权。最终,这是PAM提供的特权分离之一。
pam_unix
有一种方法可以为您检查密码。似乎web2py
的PAM实现(注意,它来自某些contrib子目录...)没有做正确的事情。也许您的PAM设置不正确,这需要更多信息才能确定;这也严重依赖于操作系统和版本/分发版。
有多个Python的PAM绑定可供使用(不幸的是标准库中没有),请使用这些绑定。对于配置,有大量的教程,请找到适合您系统的正确教程。
旧/错误的做法,不要这样做: 您不需要成为root用户,您只需要能够读取/etc/shadow
。该文件通常具有组shadow
,只有读取权限。因此,您只需要将运行PAM
检查的用户添加到shadow
组中即可。
groupadd <user> shadow
就可以解决问题了。
pam
模块是您最好的选择,但您不必直接将其嵌入到程序中。您可以编写一个简单的服务,绑定到本地主机上的端口或监听UNIX域套接字,并为同一主机上的其他进程填充PAM请求。然后,让您的web2py应用程序连接它以进行用户/密码验证。import asyncore
import pam
import socket
class Client(asyncore.dispatcher_with_send):
def __init__(self, sock):
asyncore.dispatcher_with_send.__init__(self, sock)
self._buf = ''
def handle_read(self):
data = self._buf + self.recv(1024)
if not data:
self.close()
return
reqs, data = data.rsplit('\r\n', 1)
self._buf = data
for req in reqs.split('\r\n'):
try:
user, passwd = req.split()
except:
self.send('bad\r\n')
else:
if pam.authenticate(user, passwd):
self.send('ok\r\n')
else:
self.send('fail\r\n')
def handle_close(self):
self.close()
class Service(asyncore.dispatcher_with_send):
def __init__(self, addr):
asyncore.dispatcher_with_send.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(addr)
self.listen(1)
def handle_accept(self):
conn, _ = self.accept()
Client(conn)
def main():
addr = ('localhost', 8317)
Service(addr)
try:
asyncore.loop()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
使用方法:
% telnet localhost 8317
bob abc123
ok
larry badpass
fail
incomplete
bad
最终我使用了pexpect并尝试su -用户名。 它有点慢,但效果还不错。 下面的示例还不够完善,但你会有所了解。
干杯,
Jay
#!/usr/bin/python
import pexpect
def pam(username, password):
'''Accepts username and password and tried to use PAM for authentication'''
try:
child = pexpect.spawn('/bin/su - %s'%(username))
child.expect('Password:')
child.sendline(password)
result=child.expect(['su: Authentication failure',username])
child.close()
except Exception as err:
child.close()
print ("Error authenticating. Reason: "%(err))
return False
if result == 0:
print ("Authentication failed for user %s."%(username))
return False
else:
print ("Authentication succeeded for user %s."%(username))
return True
if __name__ == '__main__':
print pam(username='default',password='chandgeme')
pexpect.spawn('/bin/su', ['-', username])
。看起来pexpect不处理";"这样的shell元字符,因此这种攻击可能不起作用,但最好还是小心为妙。 - tew-c "/bin/rm -rf /home/user/" user
。 - tew
groupadd
命令,只好使用sudo usermod -a -G shadow <user>
命令。另外需要注意的一点是,这个修改只有在重新登录后才会生效。 - cardamompam
和pam_unix
手册https://linux.die.net/man/8/pam_unix,我注意到在一个健全的应用程序中,“pam”将获取凭证并在不需要特殊权限或透露信息的情况下正确回答。看起来所提到的`web2py`实现只是做得不好。 - trapicki