Python SocketServer模块代理通讯加密问题新人求指点,pythonsocketserver,正在学习写的网页代理服务


正在学习写的网页代理服务器在对中间数据加密时出现错误,浏览器接收资源不全,
用的 SocketServer 模块,
client中:

python#!/usr/bin/env python2# conding=utf-8import sysimport socketfrom SocketServer import ThreadingMixIn, TCPServer, StreamRequestHandlerimport structimport selectimport loggingfrom AesEncrypt import AesEncryptimport hashlibdef encrypt(data):    newencrypt = AesEncrypt()    psw = 'admin'    salt = '123456'    newencrypt.md5(psw,salt)    return newencrypt.encrypt(data)def decrypt(data):    newdecrypt = AesEncrypt()    psw = 'admin'    salt = '123456'    newdecrypt.md5(psw,salt)    return newdecrypt.decrypt(data)def sendall(sock,data):    length = 0    while True:        result = sock.send(data[length:])        if result < 0:            return result        length += result        if length == len(data):            return lengthclass Log():    def __init__(self):        self.logger = logging.getLogger('log')        self.logger.setLevel(logging.DEBUG)        f = logging.FileHandler('./log')        f.setLevel(logging.DEBUG)        self.logger.addHandler(f)    def log(self, data):        self.logger.info(data)class Server(ThreadingMixIn,TCPServer):passclass Socks5Server(StreamRequestHandler):    def handleData(self, source, dest):        try:            while 1:                active, w, x= select.select([source, dest], [], [], 5)                if not active:                    break                if source in active:                    data = source.recv(4096)                    if len(data) <= 0:                        break                    data = encrypt(data)                    re = sendall(dest,data)                    #re = dest.send(data)                    if re < len(data):                        raise Exception('Failed to send all data')                if dest in active:                    data = dest.recv(4096)                    if len(data) <= 0:                        break                    data = decrypt(data)                    re = sendall(source,data)                    #re = source.send(data)                    if re < len(data):                       raise Exception('Failed to send all data')        finally:            self.log.log('closed')            source.close()            dest.close()    def handle(self):        self.log = Log()        socks = self.connection        socks.recv(262)        socks.send("\x05\x00")        data = self.rfile.read(4)        #print data        mode = ord(data[1])        if mode !=1:            logging.warn('mode !=1')            return        addrtypr = ord(data[3])        addr_to_send = data[3]        if addrtypr == 1:            addr_ip = self.rfile.read(4)            addr = socket.inet_ntoa(addr_ip)            addr_to_send += addr_ip        elif addrtypr == 3:            addr_len = self.rfile.read(1)            addr = self.rfile.read(ord(addr_len))            addr_to_send += addr_len +addr        else:            logging.warn('addr_type not support')            return        addr_port = self.rfile.read(2)        addr_to_send += addr_port        port = struct.unpack('>H', addr_port)        reply = "\x05\x00\x00\x01"        reply += socket.inet_aton('0.0.0.0') + struct.pack('>H', 2222)        self.wfile.write(reply)        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        sock.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1)        sock.connect(('127.0.0.1', 1083))        sock.send(addr_to_send)        self.handleData(socks, sock)        logging.info('connecting %s:%s'%(addr,port[0]))if __name__=="__main__":    HOST, PORT="localhost", 8088    try:        server = Server((HOST, PORT), Socks5Server)        server.serve_forever()    except KeyboardInterrupt:        server.shutdown()        sys.exit()

server中:

python#!/user/bin/env python2# conding=utf-8from AesEncrypt import AesEncryptfrom SocketServer import StreamRequestHandler, ThreadingMixIn, TCPServerimport socketimport structfrom select import selectimport loggingimport hashlibdef encrypt(data):    newencrypt = AesEncrypt()    psw = 'admin'    salt = '123456'    newencrypt.md5(psw,salt)    return newencrypt.encrypt(data)def decrypt(data):    newdecrypt = AesEncrypt()    psw = 'admin'    salt = '123456'    newdecrypt.md5(psw,salt)    return newdecrypt.decrypt(data)def sendall(sock,data):    length = 0    while True:        result = sock.send(data[length:])        if result <0:            return result        length += result        if length == len(data):            return lengthclass ServerThread(ThreadingMixIn, TCPServer):    passclass Server(StreamRequestHandler):    def handle(self):        socks = self.connection        addrtype = ord(socks.recv(1))        if addrtype == 1:            addr = socket.inet_ntoa(self.rfile.read(4))        elif addrtype == 3:            addr = self.rfile.read(ord(socks.recv(1)))        else:            logging.warn('addr type not support')            return        port = struct.unpack('>H', self.rfile.read(2))        logging.info('connecting %s:%d'%(addr,port[0]))        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        client.setsockopt(socket.IPPROTO_TCP,socket.TCP_NODELAY,1)        client.connect((addr, port[0]))        try:            while 1:                active, w, x = select([socks, client], [], [])                if not active:                    break                if socks in active:                    data = socks.recv(4096)                    if len(data)<= 0:                        break                    data = decrypt(data)                    re = sendall(client,data)                    #re = client.send(data)                    if re < len(data):                        raise Exception('Failed to send all data')                if client in active:                    data = client.recv(4096)                    if len(data) <= 0:                        break                    data = encrypt(data)                    re = sendall(socks,data)                    #re = socks.send(data)                    #undata = decrypt(data)                    if re < len(data):                        raise Exception('Failed to send all data')        finally:            print 'closed!!!'            client.close()            socks.close()if __name__== "__main__":    HOST, PORT="localhost", 1083    server = ServerThread((HOST, PORT), Server)    server.serve_forever()

AesEncrypt.py:

python# coding=utf-8from Crypto.Cipher import AESfrom binascii import b2a_hex, a2b_heximport hashlibclass AesEncrypt(object):    def md5(self, psw, salt):        self.hasli = salt + psw        self.MD5 = hashlib.md5(self.hasli).hexdigest()        self.KEY = self.MD5[0:16]        self.IV = self.MD5[16:]    def encrypt(self, data):        length = 16        count = len(data)        if count == 0:            return data        elif count < length:            add = (length - count)            data = data + ('$' * add)        elif count > length:            if count % length == 0:                data = data            else:                add = (length - (count % length))                data = data + ('$' * add)        obj = AES.new(self.KEY, AES.MODE_CBC, self.IV)        cipherdata = obj.encrypt(data)        #cipherdata = b2a_hex(cipherdata)        return cipherdata    def decrypt(self, cipherdata):        if len(cipherdata) == 0:            return cipherdata        else:            obj = AES.new(self.KEY, AES.MODE_CBC, self.IV)            #data = a2b_hex(cipherdata)            data = obj.decrypt(cipherdata)            data = data.rstrip('$')            return data

encrypt()是加密函数,decrypt()解密,用的是AES加密,因为不足16位倍数时需要补位,但解密后会删掉补位的字符。
开始代理后,结果网页加载不全,一般只能打开一部分资源,大部分加载不出来(如不能获取css,js,图片等等,但都是随机会少一些资源。)。
因为对TCP协议不是很了解,用wireshark抓包分析也看不出什么,
比较收到、发出的数据包的md5值也是一样,不知道哪出了问题,新人求指点啊~~~
sockcs.sendall() 也是使用过,有时候会爆出error: [Errno 104] Connection reset by peer

代码看完了,结论是:你不懂加密。

你这样做的结果除了不安全之外,你必须保证每次加密和对应的解密的数据是同一段数据,但是你没有做这种保证。经常会出现你加密了4096字节数据发过去,对方收到了2048字节就去解密,后边的2048字节使用新初始化的对象进行解密。所以数据才会不正确。

写网络程序的时候要注意不完整的 recv 和 send(实际处理的数据量小于预期)。而写加密程序的时候要注意你很可能根本不懂加密(这里有四个链接哦)。

建议使用现成的 TLS/SSL。

编橙之家文章,

评论关闭