如何让键盘记录器更难受
这种安全的文本框欺骗键盘记录器。
介绍
如果您通常 在桌面应用程序中 输入密码, 那么 键盘记录器 可能会窃取 您的秘密。 这显然 不好。 屏幕键盘 可能是一个 不错的解决方案, 但同样, 也可能存在 一个屏幕截图 程序 轻松地 监视 您的密码。 此外, 屏幕键盘 相对 不方便。
以下文章 介绍了一个 相对简单的 原理, 该原理 可防止 键盘记录器 记录输入的 密码。 基本上, 所使用的 系统 出奇地简单, 因此 可以移植到 其他编程 / 操作系统 / 平台, 尽管 存在 一些 小的 限制。
背景
第一个问题是:程序如何隐藏按键?也许有一些困难的方法可以做到这一点,但这很可能是不可能的。我们做一个假设:输入的字符必然意味着键盘记录器可以看到它们。而这正是我们用来对付键盘记录器的。
第二个问题是:程序如何生成按键?这通常是可能的。例如,我们在 C# 中使用 `SendKeys` 类,它提供了发送按键的方法。顺便说一句,可能会有前面提到的限制,因为网站没有生成按键的权限。
第三个问题是:我们如何结合这两个陈述?每当用户输入一个字符时,程序就会多生成一些按键。键盘记录器会记录用户和程序的全部字符,但只有用户和程序知道整个密码。未经授权的第三方只会看到一堆乱码,无法解密主密码。
第四个问题是:这个主系统100%安全吗?令人惊讶且不幸的是,不是。该原理有很多薄弱环节,但也有很多解决方案可以弥补这些差距。我建议所有开发者在将此概念添加到代码之前都要仔细考虑。让我向您解释一下漏洞和解决方案:
在每个字符之后创建随机按键,可以让攻击者重现输入的密码。因此,程序必须创建相同的按键。然而,生成的按键对于所有密码都不应该是相同的。总之,我们需要一个算法,该算法为每个字符始终生成相同的按键。此外,生成的按键的长度应该有所不同。
然而,攻击者可以通过逆向工程或测试来创建一个包含所有字符及其哈希结果的表。使用此表,他可以相对容易地解密密码。为防止这种情况,生成的按键应取决于密码的身份,如账户名、账户号、电子邮件或计算机规格。不幸的是,这只是一个障碍,而不是对攻击者的阻碍。
使用代码
首先,创建一个具有某些属性的新 组件 `SecureTextBox`。
public class SecureTextBox : TextBox
{
/// <summary>
/// Gets the typed password.
/// </summary>
public string Password
{
get;
private set;
}
/// <summary>
/// Sets or gets the password ID.
/// </summary>
public string ID
{
get;
set;
}
}
下一步是实现一个构造函数来初始化重要的事件。
public SecureTextBox()
{
this.TextChanged += new EventHandler(SecureTextBox_TextChanged);
this.KeyDown += new KeyEventHandler(SecureTextBox_KeyDown);
this.KeyUp += new KeyEventHandler(SecureTextBox_KeyUp);
}
`SecureTextBox_KeyDown` 和 `SecureTextBox_KeyUp` 方法应确保不按下任何键,否则字符将被错误地插入甚至不插入。布尔变量 `IsTriggering` 声明用户在按住另一个键时是否输入了字符。
private int KeysPressed = 0;
private bool IsTriggering = false;
void SecureTextBox_KeyDown(object sender, KeyEventArgs e)
{
KeysPressed++;
}
void SecureTextBox_KeyUp(object sender, KeyEventArgs e)
{
KeysPressed--;
if (KeysPressed == 0 & IsTriggering)
this.SecureTextBox_TextChanged(null, null);
}
现在考虑随机函数。在这个例子中,我使用了 `Random` 结合给定的种子。种子是从 `ID` 和用户上次输入的字符创建的。
Random _NextSaltLength, _NextSaltChar;
// TODO: Extend the CharContent with all important characters!
string CharContent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
private int NextSaltLength(bool CreateNew)
{
// TODO: Replace this code with your own function!
if (CreateNew)
_NextSaltLength = new Random(ID.GetHashCode() - Password[Password.Length - 1].GetHashCode());
return _NextSaltLength.Next(1, 4);
}
private string NextSaltChar(bool CreateNew)
{
// TODO: Replace this code with your own function!
if (CreateNew)
_NextSaltChar = new Random(ID.GetHashCode() + Password[Password.Length - 1].GetHashCode());
return CharContent[_NextSaltChar.Next(CharContent.Length)].ToString();
}
最后,我们可以创建管理按键生成的主方法。
private int RemainingSaltChars = 0;
private int LastTextLength = 0;
void SecureTextBox_TextChanged(object sender, EventArgs e)
{
if (KeysPressed > 0)
{
IsTriggering = true;
return;
}
IsTriggering = false;
if (LastTextLength < this.TextLength)
{
LastTextLength = this.TextLength;
if (RemainingSaltChars > 0)
{
if (RemainingSaltChars > 1)
SendKeys.Send(this.NextSaltChar(false));
RemainingSaltChars--;
}
else
{
this.Password += this.Text[this.TextLength - 1];
RemainingSaltChars = this.NextSaltLength(true);
SendKeys.Send(this.NextSaltChar(true));
}
}
else
{
this.ResetText();
LastTextLength = 0;
}
}
这是实现的简要说明:如果没有按键按下,并且用户在 `TextBox` 中输入了一个字符,该字符将被保存,下一个生成的字符数量将被随机计算,第一个字符通过 `SendKeys.Send()` 发送。现在程序处于一个复杂的循环中,生成指定的按键。当 `RemainingSaltChars` 为零时,此状态会被中断。顺便说一句,如果用户按下 Delete 或 Backspace,文本将被重置,因为否则会混淆算法。
public override void ResetText()
{
base.ResetText();
this.Password = String.Empty;
}
兴趣点
最初,我从一个在启动时轮询密码的软件那里获得了这个原理。起初我奇怪为什么文本框中出现的掩码字符比输入的要多,直到我弄明白了。我实现了我的想法,并使用键盘记录器对我的代码进行了实验。我对效果感到非常惊讶。然后我想分析一下当使用键盘记录器时,另一个应用程序的运行效果如何。但是,该程序没有生成任何按键。真不敢相信!我发现这非常有趣。
在引言中,我说这个原理无法由网站实现。解决这个问题的方法是创建一个额外的浏览器插件,它可以承担这项任务。
历史
发布于 2013 年 1 月 19 日。