Модуль secret. py

modul secret py Сервер PyMailCGI

Как вы уже могли понять, безопасность в Веб является слишком объемной темой, чтобы ее можно было рассмотреть здесь. Вследствие этого модуль secret.py, представленный в примере 16.13, старается обойти эту проблему, обеспечивая различные варианты ее решения:

     Если у вас есть возможность получить и установить стороннюю систему PyCrypto, описанную выше, модуль будет использовать инструменты шифрования по алгоритму AES из этого пакета для шифрования пароля при передаче вместе с именем пользователя.

     В противном случае следующей будет попытка использовать пакет rotor, если вам удастся отыскать и установить оригинальный модуль rotor для используемой вами версии Python.

     И, наконец, в крайнем случае он будет использовать реализацию простейшего алгоритма шифрования, основанного на искажении символов, которую вы сможете заменить своей реализацией при установке программы в Интернете.

Дополнительные детали смотрите в примере 16.13 — там используются определения функций, вложенные в условные инструкции if, которые позволяют сгенерировать функции для выбранной схемы шифрования во время выполнения.

Пример 16.13. PP4E\Internet\Web\PyMailCgi\cgi-bin\secret.py

############################################################################ PyMailCGI шифрует пароль, когда он пересылается клиенту или от него через сеть вместе с именем пользователя в скрытых полях форм или в параметрах запроса URL; использует функции encode/decode в этом модуле для шифрования пароля — выгрузите на сервер собственную версию этого модуля, чтобы использовать другой механизм шифрования; PyMailCGI не сохраняет пароли на сервере и не отображает его при вводе пользователем в форме ввода, но это не дает 100% защиты — файл этого модуля сам может оказаться уязвим; использование протокола HTTPS может оказаться более удачным и более простым решением, но классы реализации веб-сервера в стандартной библиотеке Python не поддерживают его;

############################################################################

import sys, time

dayofweek = time.localtime(time.time())[6] # для реализации собственных схем forceReadablePassword = False

############################################################################ # схемы преобразования строк

############################################################################

if not forceReadablePassword:

########################################################################

#  по умолчанию не делать ничего: вызовы urllib.parse.quote

#  или cgi.escape в commonhtml.py выполнят необходимое экранирование

#  пароля для встраивания его в URL или HTML; модуль cgi

# автоматически выполнит обратное преобразование;

######################################################################## def stringify(old): return old

def unstringify(old): return old

else:

########################################################################

#  преобразование кодированной строки в/из строки цифр,

#  чтобы избежать проблем с некоторыми специальными/непечатаемыми

#  символами, но сохранить возможность чтения результата

#  (хотя и зашифрованного); в некоторых броузерах есть проблемы

#  с преобразованными амперсандами и т.д.;

#  ####################################################################### separator =

def stringify(old):

new = »

for char in old:

ascii = str(ord(char))

new = new + separator + ascii # ‘-ascii-ascii-ascii’

return new

def unstringify(old):

new = »

for ascii in old.split(separator)[1:]:

new = new + chr(int(ascii))

return new

##################################################

#   схемы шифрования: пробует PyCrypto, затем rotor,

#   затем простейший/нестандартный алгоритм

##################################################

useCrypto = useRotor = True

try:

import Crypto

except:

useCrypto = False

try:

import rotor

except:

useRotor = False

if useCrypto:

###########################################################

#   использовать алгоритм AES из стороннего пакета pycrypto

#   предполагается, что в конце строки пароля отсутствует

#   символ ‘\0’: используется для дополнения справа

#   измените закрытый ключ здесь, если используете этот метод

###########################################################

sys.stderr.write(‘using PyCrypto\n’)

from Crypto.Cipher import AES

mykey = ‘pymailcgi3’.ljust(16, ‘-‘) # ключ должен иметь длину 16, 24

# или 32 байта

def do_encode(pswd):

over = len(pswd) % 16

if over: pswd += ‘\0’ * (16-over) # дополнение: длина должна быть

aesobj = AES.new(mykey, AES.MODE_ECB) # кратна 16

return aesobj.encrypt(pswd)

def do_decode(pswd):

aesobj = AES.new(mykey, AES.MODE_ECB)

pswd = aesobj.decrypt(pswd)

return pswd.rstrip(‘\0’)

elif useRotor:

############################################################

#   использовать для шифрования стандартный модуль rotor

#   он лучше подходит для шифрования, чем программный код выше

#   к сожалению, он больше недоступен в Py 2.4+

############################################################

sys.stderr.write(‘using rotor\n’)

import rotor

mykey = ‘pymailcgi3’

def do_encode(pswd):

robj = rotor.newrotor(mykey) # использовать алгоритм enigma

return robj.encrypt(pswd)

def do_decode(pswd):

robj = rotor.newrotor(mykey)

return robj.decrypt(pswd)

else:

##############################################################

#   в крайнем случае использовать собственную схему, основанную

#   на искажении символов некоторым обратимым способом

#   предупреждение: слишком простой алгоритм — замените своим

##############################################################

sys.stderr.write(‘using simple\n’)

adder = 1

def do_encode(pswd):

pswd = ‘vs’ + pswd + ’48’

res = »

for char in pswd:

res += chr(ord(char) + adder) # увеличить каждый код ASCII

return str(res)

def do_decode(pswd):

pswd = pswd[2:-2]

res = »

for char in pswd:

res += chr(ord(char) adder)

return res

############################################################################

# функции верхнего уровня

############################################################################

def encode(pswd):

return stringify(do_encode(pswd)) # шифрование плюс

# преобразование строки

def decode(pswd):

return do_decode(unstringify(pswd))

В дополнение к шифрованию в этом модуле реализованы также методы преобразования уже зашифрованных строк, которые преобразуют их содержимое в печатаемые символы и обратно. По умолчанию функции преобразования ничего не делают, и система полностью полагается на то, что зашифрованные пароли будут корректно обработаны функциями экранирования URL и HTML. Дополнительная схема преобразования транслирует зашифрованные строки в строки, содержащие цифровые коды ASCII символов, разделенные дефисами. Такой метод позволяет преобразовать непечатаемые символы в зашифрованной строке в печатаемые.

Для иллюстрации проверим инструменты из этого модуля в интерактивном режиме. В этих тестах переменной forceReadablePassword было присвоено значение True. Функции верхнего уровня encode и decode будут воспроизводить печатаемые символы (для иллюстрации этот тест проводился в Python 2.X с установленным пакетом PyCrypto):

>>> from secret import *

using PyCrypto

>>> data = encode(‘spam@123+’)

>>> data

‘-47-248-2-170-107-242-175-18-227-249-53-130-14-140-163-107’

>>> decode(data)

spam@123+’

А ниже шифрование выполняется в два этапа — собственно шифрование и преобразование в печатаемые символы:

>>> raw = do_encode(‘spam@123+’)

>>> raw

‘/\xf8\x02\xaak\xf2\xaf\x12\xe3\xf95\x82\x0e\x8c\xa3k’

>>> text = stringify(raw)

>>> text

‘-47-248-2-170-107-242-175-18-227-249-53-130-14-140-163-107’

>>> len(raw), len(text)

(16, 58)

Ниже показано, как выглядит шифрование без дополнительного преобразования в печатаемые символы:

>>> raw = do_encode(‘spam@123+’)

>>> raw

‘/\xf8\x02\xaak\xf2\xaf\x12\xe3\xf95\x82\x0e\x8c\xa3k’

>>> do_decode(raw)

spam@123+’

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий