Безопасное стирание пароля в памяти (Python) - PullRequest
41 голосов
/ 08 апреля 2009

Как сохранить пароль, введенный пользователем, в памяти и надежно стереть его после того, как он больше не нужен?

Для уточнения, в настоящее время у нас есть следующий код:

username = raw_input('User name: ')
password = getpass.getpass()
mail = imaplib.IMAP4(MAIL_HOST)
mail.login(username, password)

После вызова метода login, что нам нужно сделать, чтобы заполнить область памяти, содержащую пароль искаженными символами, чтобы кто-то не смог восстановить пароль, выполнив дамп ядра?

Есть похожий вопрос, однако он есть в Java, и в решении используются символьные массивы: Как надежно хранить хеши паролей в памяти при создании учетных записей?

Можно ли это сделать в Python?

Ответы [ 7 ]

39 голосов
/ 08 апреля 2009

Python не имеет такого низкого уровня контроля над памятью. Примите это и двигайтесь дальше. best , который вы можете сделать, это del password после вызова mail.login, чтобы не осталось ссылок на объект строки пароля. Любое решение, которое подразумевает возможность сделать больше, чем просто дает вам ложное чувство безопасности.

Строковые объекты Python являются неизменяемыми; нет прямого способа изменить содержимое строки после ее создания. Даже если вам удастся каким-либо образом перезаписать содержимое строки, на которую указывает password (что технически возможно с глупыми трюками ctypes), все равно будут другие копии пароля, созданные в различные строковые операции:

  • модулем getpass, когда он удаляет завершающий символ новой строки введенного пароля
  • модулем imaplib, когда он цитирует пароль, а затем создает полную команду IMAP перед передачей его в сокет

Вам как-то придется получать ссылки на все эти строки и перезаписывать их память.

19 голосов
/ 18 ноября 2009

На самом деле - это способ безопасного удаления строк в Python; используйте функцию memset C согласно Пометить данные как чувствительные в python

Отредактировано, чтобы добавить, спустя долгое время после того, как сообщение было сделано: вот более глубокое погружение в интернирование строки . Существуют некоторые обстоятельства (в основном связанные с неконстантными строками), когда интернирование не происходит, что делает очистку строкового значения несколько более явной, основываясь на подсчете ссылок CPython GC. (Хотя это еще не «очистка» / «очистка»).

6 голосов
/ 08 апреля 2009

Если вам не нужно, чтобы почтовый объект сохранялся после завершения работы с ним, я думаю, что вам лучше всего выполнить почтовую работу в подпроцессе (см. Модуль подпроцесс ). Таким образом , когда подпроцесс умирает, значит и ваш пароль.

1 голос
/ 20 августа 2018

Правильным решением является использование bytearray () ..., который является изменяемым, и вы можете безопасно удалять ключи и чувствительный материал из оперативной памяти.

Однако, есть некоторые библиотеки, в частности, библиотека "cryptography" python, которая не позволяет использовать "bytearray". Это проблематично ... в некоторой степени эти криптографические библиотеки должны обеспечивать, чтобы только изменяемые типы использовались для ключевого материала.

Существует SecureString, представляющий собой пип-модуль, который позволяет полностью удалить ключ из памяти ... (я немного изменил его рефакторинг и назвал его SecureBytes). Я написал несколько модульных тестов, которые показывают, что ключ полностью удален.

Но есть большая оговорка: если чей-то пароль "type", то слово "type" будет стёрто со всего python ... в том числе в определениях функций и атрибутах объектов.

Другими словами ... мутирование неизменяемых типов - ужасная идея, и, если вы не будете очень осторожны, можете немедленно завершить работу любой работающей программы.

Правильное решение ... никогда не используйте неизменяемые типы для ключевого материала, паролей и т. Д. Любой, кто создает криптографическую библиотеку или подпрограмму, такую ​​как "getpass", должен работать с "bytearray" вместо строк python.

1 голос
/ 23 июля 2015

Это можно сделать с помощью 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[:] = ''

Вам необходимо определить максимальный размер пароля, но при этом данные должны быть удалены при перезаписи.

0 голосов
/ 08 апреля 2009

Сохраните пароль в списке, и если вы просто установите список в нуль, память массива, сохраненного в списке, автоматически освобождается.

0 голосов
/ 08 апреля 2009

РЕДАКТИРОВАТЬ: убрал плохой совет ...

Вы также можете использовать массивы, такие как пример Java, если хотите, но достаточно просто перезаписать их.

http://docs.python.org/library/array.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...