[英]How to secure a Python distributed computing layer
这些模块旨在促进跨多台计算机的计算能力层。 有哪些一种或多种经过验证的方法可以防止欺骗数据包? 我怎样才能最好地制作传输的可调用对象引用的任何未包含对象的深层副本? function object 是封装客户端作业的最佳方法吗? 最后:这个代码可以改进吗? 后记:请原谅我的最后一个问题。 我需要挽回我的名誉。
袜子.py
from socket import socket
from socket import AF_INET
from socket import SOCK_STREAM
from socket import gethostbyname
from socket import gethostname
class SocketServer:
def __init__(self, port):
self.sock = socket(AF_INET, SOCK_STREAM)
self.port = port
def send(self, tdata):
self.sock.bind(("127.0.0.1", self.port))
self.sock.listen(len(tdata))
while tdata:
s = self.sock.accept()[0]
for x in tdata.pop(): s.send(x)
s.close()
self.sock.close()
class Socket:
def __init__(self, host, port):
self.sock = socket(AF_INET, SOCK_STREAM)
self.sock.connect((host, port))
def recv(self, size):
return self.sock.recv(size)
def close(self):
self.sock.close()
包.py
#http://stackoverflow.com/questions/6234586/we-need-to-pickle-any-sort-of-callable
from marshal import dumps as marshal_dumps
from pickle import dumps as pickle_dumps
from struct import pack as struct_pack
from hashlib import sha224
class packer:
def __init__(self):
self.f = []
def pack(self, what):
if type(what) is type(lambda:None):
self.f = []
self.f.append(marshal_dumps(what.func_code))
self.f.append(pickle_dumps(what.func_name))
self.f.append(pickle_dumps(what.func_defaults))
self.f.append(pickle_dumps(what.func_closure))
self.f = pickle_dumps(self.f)
return (struct_pack('Q', len(self.f)), self.f)
return None
def gethash(self):
hash = sha224(self.f).hexdigest()
return (struct_pack('Q', len(hash)), hash)
def getwithhash(self, what):
a, b = self.pack(what)
c, d = self.gethash()
return (a, b, c, d)
解包.py
from types import FunctionType
from pickle import loads as pickle_loads
from marshal import loads as marshal_loads
from struct import unpack as struct_unpack
from struct import calcsize
from hashlib import sha224
#http://stackoverflow.com/questions/6234586/we-need-to-pickle-any-sort-of-callable
class unpacker:
def __init__(self):
self.f = []
self.fcompiled = lambda:None
self.sizeofsize = calcsize('Q')
def unpack(self, sock):
size = struct_unpack('Q', sock.recv(self.sizeofsize))[0]
self.f = sock.recv(size)
size = struct_unpack('Q', sock.recv(self.sizeofsize))[0]
hash0 = sock.recv(size)
sock.close()
hash1 = sha224(self.f).hexdigest()
if hash0 != hash1: return None
self.f = pickle_loads(self.f)
a = marshal_loads(self.f[0])
b = globals() # TODO
c = pickle_loads(self.f[1])
d = pickle_loads(self.f[2])
e = pickle_loads(self.f[3])
self.fcompiled = FunctionType(a, b, c, d, e)
return self.fcompiled
测试.py
from unpack import unpacker
from pack import packer
from sock import SocketServer
from sock import Socket
from threading import Thread
from time import sleep
count = 2
port = 4446
def f():
print 42
def server():
ss = SocketServer(port)
pack = packer()
functions = [pack.getwithhash(f) for nothing in range(count)]
ss.send(functions)
if __name__ == "__main__":
Thread(target=server).start()
sleep(1)
unpack = unpacker()
for nothing in range(count):
print unpack.unpack(Socket("127.0.0.1", port))
output:
<function f at 0x0000000>
<function f at 0x0000000>
我现在仔细查看了您的代码,并且有一些评论:
sha224
是一种出色的散列算法,并且很容易注意到被意外修改的数据包可能仍然通过TCP 校验和。仅使用哈希算法不能证明数据包的来源,也不能证明数据包没有被恶意修改:攻击者可以简单地在修改数据后重新计算 hash 并重新发送数据包。
有几种“常用方法”来解决这个问题:您可以使用共享密钥,即参与网络的所有客户端之间共享的密钥。 此密钥将用作密钥哈希的一部分,例如HMAC ,数据接收者将使用共享密钥重新计算 HMAC 身份验证代码。 它既快速又简单(在某些禁止加密软件的司法管辖区是合法的),但如果任何一个系统的密钥被泄露,共享密钥就是一项巨大的责任。 (受损系统甚至可能不是您的威胁 model 的一部分。)
您还可以使用按主机付费的共享密钥。 它就像所有节点之间的共享密钥一样工作,但在单个客户端密钥被泄露的情况下,只需在所有其他系统上替换一个客户端的密钥。
您还可以使用公钥加密为数据包提供签名。 每个客户端都有一个私钥和一个所有客户端都知道的对应公钥。 泄露的私钥仍然会破坏系统,但它大大减少了您需要准备的密钥数量。 (每个客户端只有一个,而不是每对客户端一个:O(N) vs O(N 2 )。)
公钥系统将自己写成一种学习体验很有趣,但尝试正确编程却很糟糕。 防止重放攻击、选择性消息丢弃、消息切片/构造等,需要大量巧妙的协议设计。
因此,大多数人部署了预制的传输安全方案,例如 SSLv3 或TLS 。 结合客户端证书,它可以很容易地保证两个端点都是他们所说的(当然,直到密钥被泄露) ,并保证在受 TLS 保护的 stream 中发送的数据以正确的顺序交付并且没有篡改。
正确配置 TLS 可能需要做很多工作。 使用更简单的工具(例如ssh )可能会取得同样的成功。 库是可用的,因此您可以通过编程方式控制连接,而不是依赖系统提供的ssh(1)
客户端和sshd(8)
服务器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.