понедельник, 19 октября 2020 г.

Подставляем пароль в KeePass с флешки

Ручной ввод пароля в KeePass можно заменить вставкой флешки, где этот пароль будет храниться. Телодвижения станут минимальными — только вставка флешки, после чего KeePass автоматически запустится, а флешка отключится.

Флешке понадобится назначить какое-либо имя и создать на ней создать текстовый файл с паролем.

В подкаталоге Scripts каталога программы понадобится создать скрипт:

Скрипт AutoStart.js
// пути к базе, ключевому файлу и файлу конфигурации (если используются)
// указывать абсолютные или относительно каталога KeePass,
// скрипт поместить в его подкаталог Scripts

// путь к базе
var database = 'DBases\\Database.kdbx';

// дополнительные аргументы командной строки KeePass,
// например, ключевой файл, шифрование учетной записью, файл конфигурации, сворачивание окна:
// '-keyfile:"E:\\Keys\\Database.key" -useraccount -cfg-local:"KeePass.config.xml" -minimize'
var cmdLine = '';

// метка флешки (в нижнем регистре)
var label = 'key drive';

// путь к файлу с паролем относительно корня флешки
var pwPath = 'Utilities\\Password.txt';


var WshShell = WScript.CreateObject('WScript.Shell');
var ProcEnv = WshShell.Environment('process');
var FSO = WScript.CreateObject('Scripting.FileSystemObject');
var Shell = WScript.CreateObject("Shell.Application");
var WmiService = GetObject("WinMgmts:{impersonationLevel=impersonate}!//./root/cimv2");

WshShell.CurrentDirectory = WScript.ScriptFullName.slice(0, -WScript.ScriptName.length) + '..';
setEnvVariables();

var eventSource = WmiService.ExecNotificationQuery(
	"SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2");
do {
	var drive = eventSource.NextEvent().DriveName;
} while (!matchDriveToLabel(drive, label));

var password = readFile(drive + '\\' + pwPath);
try {
	Shell.NameSpace(17).ParseName(drive).InvokeVerb("Eject");
} catch (e) {
}
try {
	WshShell.Exec('KeePass.exe "' + database + '" -pw-stdin ' + cmdLine)
		.StdIn.WriteLine(password);
} catch (e) {
}
WshShell.Run('"' + WScript.FullName + '" "' + WScript.ScriptFullName + '"');
WScript.Sleep(2000);


function matchDriveToLabel(drive, label) {
	try {
		return FSO.GetDrive(drive).VolumeName.toLowerCase() == label;
	} catch (e) {
		return false;
	}
}

function readFile(path) {
	var text = '';
	try {
		try {
			var textStream = FSO.OpenTextFile(path, 1, false, 0);
			text = textStream.readAll();
		} finally {
			textStream.close();
		}
	} catch (e) {
	}
	return text;
}

function setEnvVariables() {
	/* переменным среды присваиваются явные значения */
	
	// абсолютный путь к каталогу с базами
	ProcEnv('KeePass_DBDir') = WshShell.CurrentDirectory + '\\DBases';
	
	// путь к каталогу с бэкапами
	ProcEnv('KeePass_BackupDir') = 'DBases\\BackUp';
	
	// число бэкапов одной базы
	ProcEnv('KeePass_BackupCount') = '100';
	
	// путь к VeraCrypt
	ProcEnv('KeePass_VeraCrypt') = 'c:\\Program Files\\VeraCrypt\\VeraCrypt.exe';

	/* переменным среды присваивается содержимое файлов */
	setEnvVarFromFile('KeePass_TargetUrl', 'Scripts\\TargetUrl.txt');
	setEnvVarFromFile('KeePass_TargetTitle', 'Scripts\\TargetTitle.txt');
}

function setEnvVarFromFile(var_name, path) {
	var env_val = readFile(path);
	ProcEnv(var_name) = env_val ? env_val : '{C:}';
}

В коде скрипта нужно указать свой путь к базе, при необходимости, вписать оставшуюся часть командной строки (ключевой файл и т.д. — кроме базы и пароля), а также в соответствующих местах указать путь к файлу с паролем на флешке и имя этой флешки.

Дополнительно скрипт устанавливает переменные среды, аналогично предложенному в статье о параметрах запуска. Их можно проигнорировать или, если они применяются, задать по-своему, отредактировав функцию setEnvVariables().

Имеет смысл настроить автозапуск скрипта (т.е. команды %windir%\System32\wscript.exe "путь\к\скрипту"), например, планировщиком. Скрипт должен выполняться постоянно: для завершения понадобится удалить его процесс в диспетчере задач.

При вставке флешки KeePass будет запускаться заново, поэтому желательно включить в нем либо опцию «Безопасность → Всегда выход, а не блокировка программы», либо опцию «Дополнительно → Запретить запуск нескольких копий программы».

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

Чтобы защититься от утечки при попадании флешки на другие ПК, имеет смысл отформатировать ее в NTFS и включить в свойствах файла или каталога EFS-шифрование. Другой способ защиты — открывать флешкой вспомогательную базу, зашифрованную случайным паролем и данными учетной записи и содержащую пароль и ключевой файл основной базы, которая будет затем открываться триггером.