Безопасное стирание пароля в памяти (Python)
Как вы храните пароль, введенный пользователем в память, и надежно стираете его после того, как он больше не нужен?
Чтобы уточнить, в настоящее время мы имеем следующий код:
username = raw_input('User name: ')
password = getpass.getpass()
mail = imaplib.IMAP4(MAIL_HOST)
mail.login(username, password)
После вызова метода login
, что нам нужно сделать, чтобы заполнить область памяти, содержащую пароль с искаженными символами, чтобы кто-то не смог восстановить пароль, выполнив дамп ядра?
Есть аналогичный вопрос, однако он находится в Java, и решение использует массивы символов:
Как безопасно хранить хэширование пароля в памяти при создании аккаунтов?
Можно ли это сделать в Python?
Ответы
Ответ 1
Python не обладает таким низким уровнем контроля над памятью. Примите это и продолжайте. лучший, который вы можете сделать, это del password
после вызова mail.login
, чтобы ссылки на объект строки пароля не сохранялись. Любое решение, которое претендует на возможность сделать больше, это лишь дает вам ложное чувство безопасности.
Строковые объекты Python неизменяемы; нет прямого способа изменить содержимое строки после ее создания. Даже если вы каким-то образом перезаписали содержимое строки, на которую ссылается password
(что технически возможно с помощью глупых трюков ctypes), все равно будут другие копии пароля, которые были созданы в различных строковых операциях:
- с помощью модуля getpass, когда он удаляет завершающую новую строку с введенного пароля
- модулем imaplib, когда он цитирует пароль, а затем создает полную команду IMAP перед передачей ее в сокет
Вам нужно было бы получить ссылки на все эти строки и перезаписать их память.
Ответ 2
На самом деле - это способ безопасного удаления строк в Python; используйте функцию memset C согласно Пометить данные как чувствительные в python
Отредактировано, чтобы добавить, спустя долгое время после того, как сообщение было сделано: здесь более глубокое погружение в интернирование строки. Существуют некоторые обстоятельства (в основном связанные с неконстантными строками), когда интернирование не происходит, что делает очистку строкового значения несколько более явной, основываясь на подсчете ссылок CPython GC. (Хотя это еще не "очистка"/"очистка").
Ответ 3
Если вам не нужно, чтобы почтовый объект сохранялся, как только вы закончите с ним, я думаю, что лучше всего выполнить работу по рассылке в подпроцессе (см. subprocess.) Таким образом, когда подпроцесс умирает, так же ваш пароль.
Ответ 4
Это можно сделать с помощью numpy chararray:
import numpy as np
username = raw_input('User name: ')
mail = imaplib.IMAP4(MAIL_HOST)
x = np.chararray((20,))
x[:] = list("{:<20}".format(raw_input('Password: ')))
mail.login(username, x.tobytes().strip())
x[:] = ''
Вам нужно будет определить максимальный размер пароля, но это должно удалить данные, когда они будут перезаписаны.
Ответ 5
Правильным решением является использование bytearray()..., который является изменяемым, и вы можете безопасно удалять ключи и чувствительный материал из оперативной памяти.
Тем не менее, есть некоторые библиотеки, в частности, библиотека "cryptography" python, которая не позволяет использовать "bytearray". Это проблематично... в некоторой степени эти криптографические библиотеки должны обеспечивать использование только изменяемых типов для ключевого материала.
Существует SecureString, представляющий собой пип-модуль, который позволяет полностью удалить ключ из памяти... (я немного изменил его рефакторинг и назвал его SecureBytes). Я написал несколько модульных тестов, которые показывают, что ключ полностью удален.
Но есть большая оговорка: если у кого-то пароль "type", то слово "type" будет стерто со всего python... в том числе в определениях функций и атрибутах объектов.
Другими словами... мутирование неизменяемых типов - ужасная идея, и если вы не будете очень осторожны, вы можете немедленно завершить работу любой работающей программы.
Правильное решение... никогда не используйте неизменяемые типы для ключевого материала, паролей и т.д. Любой, кто создает криптографическую библиотеку или подпрограмму, такую как "getpass", должен работать с "bytearray" вместо строк python.
Ответ 6
Здесь: следующее заменяет байты адреса памяти переменной нулями, а затем разыменовывает указатель на ячейку памяти.
Протестировано на системах на основе Debian.
import sys
import ctypes
def nuke(var_to_nuke):
strlen = len(var_to_nuke)
offset = sys.getsizeof(var_to_nuke) - strlen - 1
ctypes.memset(id(var_to_nuke) + offset, 0, strlen)
del var_to_nuke # derefrencing the pointer.
Ответ 7
ИЗМЕНИТЬ: удалил плохой совет...
Вы также можете использовать массивы, например, пример java, но просто перезаписать его должно быть достаточно.
http://docs.python.org/library/array.html
Ответ 8
Сохраните пароль в списке, и если вы просто установите список в нуль, память массива, хранящегося в списке, будет автоматически освобождена.