我有一个程序会检测用户的用户名和域名,用户必须输入密码才能进入主程序。我立即读取了我将其设置为安全字符串的密码,然后我清除了文本框。我正在使用Window Form。
有人告诉我,我仍然需要在读取密码后“将内存归零”。在程序结束之前,我很难找到将内存清零的方法。
这是我处理密码的代码的一部分:
.....
domainName = txtDomain.Text;
userName = txtUsername.Text;
SecureString securePwd = ConvertToSecureString(txtPassword.Text);
txtPassword.Clear();
txtPassword.Dispose();
rSP.setUp();
// If the username or/and password is incorrect the user need to go back to fill it in again.
if (verify == false)
CheckAuthentication("http://xxxx/xxxx/default.aspx", userName, securePwd, domainName);
if (verify == true)
{
....
}
....
我知道这是将内存归零的坏方法。
当我运行调试时,我能看到密码纯文本的唯一地方是我将其传递给SecureString securePwd = ConvertToSecureString(txtPassword.Text);
并在我清除文本框之前txtPassword.Clear();
如果你能解决这个问题,我将不胜感激。
答案 0 :(得分:3)
你正在与你想要完成的事情进行一场失败的战斗。如果你想要安全性,那么使用一种语言(或控制),可以促进你本地的事情(这可以转化为更多的工作)。即使如此,总是会有(更简单的)方法来捕获在读取内存之外键入文本框的内容,因此擦除文本框内存是没有意义的,除非你能以某种方式证明客户端机器是干净且值得信赖(在这种情况下,你的问题毫无用处)。
如果你可以保证客户端的环境是干净的键盘记录器和窗口嗅探器,但由于某种原因,你仍然关注这个,那么我建议写一些可能>的本地(或不安全)C ++ em>能够使用与您试图避免的程序类似的技术将内存清零。即使在这种情况下,您也无法保证数据安全,因为从输入密码到文本框到提交表单时,始终需要时间,它将以纯文本形式显示在内存中。
如果你不得不问,那么你可能不应该在第一时间这样做,甚至我们这些天真的足够尝试的人也没有这样做没有陷阱。
<强>更新强>
经过进一步思考后,可能会通过以下方式做你所追求的事情(除了涉及键盘记录器的情况):
1. Keeping track of encrypted keys pressed in some sort of collection
2. Hooking one of the key press events on the textbox whose event handler would:
2a. Encrypt each key value using an asymmetric encryption
2b. Add it to the encrypted key collection
2c. Add an explicit password character to the textbox (or not depending on your requirements)
2d. Explicitly tell the event to ignore the key
虽然这样做所需的努力量可能超过威胁(特别是考虑到它不能防范键盘记录器),但这是可能的。这也会否定你案件SecureString
的必要性。
答案 1 :(得分:1)
......然后是什么?那么如果字符串在内存中呢?您是否担心用户计算机上的程序可以从内存中读取它?该计划可能是一个关键记录器。
如果程序在用户的计算机上运行,并且用户已登录,则程序已经可以访问网络,就像它仍然是该用户一样。您恰好正在重新使用验证方法来限制对程序的访问。但是如果目标机器感染了一些可以在程序执行期间读取内存的程序,那么它可以在整个程序执行期间读取程序的内存。
查看这一系列文章The Old New Thing。
答案 2 :(得分:0)
一些建议是:
由于内存可以存储在你的硬盘上,你应该这样做 考虑在文本框中放置一个随机字符串来制作它 覆盖而不是清除文本框。这是多硬盘 清洁工具工作。问题说明了内存,但.NET可以使用 硬盘存储如果需要,也可以像Windows一样(但这似乎是一个 牵强附加的场景)。
你还应该确保你的课程是密封的,你的 签署的程序集试图让您的类与其他人保持安全 将您的代码用作库。
您还可以考虑通过删除
来完全绕过Textbox.text
键入的每个字符。然后把收集的信息,即
将操作击键或粘贴到双向加密存储中。这
方法需要很多自定义代码,因此可能不是
优选的。
答案 3 :(得分:0)
我知道这是在很久以前就被问过的,但我觉得我可以提供我的解决方案以防万一有人偶然发现它。
我通过使用WindowsForms并将KeyPress事件捕获为常规文本框(而不是密码框)来实现此目的。我没有允许事件填充文本框,而是生成一个&#39; *&#39;字符并将字符直接插入SecureString。这样,密码永远不会在内存中......大部分都是..
首先触发KeyDown:
private void Password_KeyDown(object sender, KeyEventArgs e)
{
TextBox caller = sender as TextBox;
int position = caller.SelectionStart;
_PasswordBoxControlDown = e.Control; // toggle if control is also down
switch (e.KeyCode)
{
case Keys.Delete: //delete pressed
if (caller.SelectionLength > 0) //more than 1 character selected
{
for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
_SecurePassword.RemoveAt(caller.SelectionStart); //remove from secure password
caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength); //update textbox to reflect number of characters
KeyDownDidSomething(caller, e, position);
}
else if (caller.SelectionStart < caller.Text.Length) // nothing selected - but cursor is not at the end of textbox
{
_SecurePassword.RemoveAt(caller.SelectionStart);
caller.Text = caller.Text.Remove(caller.SelectionStart, 1);
KeyDownDidSomething(caller, e, position);
}
break;
case Keys.Back: //backspace pressed
if (caller.SelectionLength > 0) //more than 1 character selected
{
for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
_SecurePassword.RemoveAt(caller.SelectionStart); //remove from secure password
caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength); //update textbox to reflect number of characters
KeyDownDidSomething(caller, e, position);
}
else if (caller.SelectionStart > 0) // nothing selected - but cursor is not at the beginning of textbox
{
_SecurePassword.RemoveAt(caller.SelectionStart - 1);
caller.Text = caller.Text.Remove(caller.SelectionStart - 1, 1);
position--;
KeyDownDidSomething(caller, e, position);
}
break;
}
}
e.Handled = true; //tells the text box that the event has been handled, text box will not write character to text box.
caller.SelectionLength = 0;
}
private void KeyDownDidSomething(TextBox caller, KeyEventArgs e, int position)
{
//use this to do whatever you need to do when you handle an event (if at all)
}
其次是KeyPress
private const char ENTER_KEY = (char)13;
private const char CNTRL_V = (char)22;
private void Password_KeyPress(object sender, KeyPressEventArgs e)
{
TextBox caller = sender as TextBox;
char ch = e.KeyChar;
int position = caller.SelectionStart;
if (ch >= 32 && ch <= 126) //acceptable password symbol
{
int len = caller.SelectionLength;
if (caller.SelectionLength > 0) //Handles inserting when text is selected (removing selected characters)
{
for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
_SecurePassword.RemoveAt(caller.SelectionStart);
caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength);
}
_SecurePassword.InsertAt(position, ch);
caller.Text = caller.Text + '*'; //generate a * so the user knows how many characters they've entered
caller.SelectionStart = position + 1;
}
else //handle other symbol
{
switch (ch)
{
case CNTRL_V:
Password_PasteClicked(null, null); //handle paste event
break;
case ENTER_KEY:
SaveAndCloseButton_Click(null, null); //handle enter .. if you want to.
break;
//add events for any special characters here
}
}
有点让人觉得它在密码框中保存了密码。无论如何,当你完成密码时抛出_SecurePassword.Dispose()。