Board logo

标题: 保护口令:第 2 部分 [打印本页]

作者: 黑色海岸线    时间: 2004-3-29 00:37     标题: 保护口令:第 2 部分

验证用户身份
Gary McGraw 和 John Viega
Cigital (前身是 Reliable Software Technologies)
2000 年 9 月
内容:  
  
  
口令认证  
口令选择  
更多建议  
掷骰子  
口令短语  
应用程序选择的 口令  
参考资料  
关于作者  
  

在前一部分中,我们介绍了口令作为一种普遍使用的身份验证机制的概念。指出了在存储口令中某些固有的问题,并提供了一个口令存储的示例程序。在这部分中,我们将开始讨论口令系统的实质 -- 验证用户身份。
口令验证
基于口令来验证用户身份所采取的步骤看起来很简单:
读取用户名
找出用来加密原始口令的 salt
读取口令,将输入中的回显关闭
使用存储的 salt 对它运行 crypt
擦除存储口令的内存
检查两个加密的字符串是否相同
下面的代码样本是实现上述算法的一个简单程序。单击此处查看样本代码。
我们非常小心避免上一部分中编写原始口令存储程序时曾陷入过的任何陷阱。不过,上述代码样本有一个新问题 -- 在用户尝试登录到帐户时没有采取任何安全性意识的措施,而是操作失败!
当然,程序在三次错误登录尝试后停止,但那又怎么样呢?人们可以一遍一遍地运行程序。这样,攻击者要猜出他们想闯入的帐户的口令可以有无限次的尝试机会。这差不多和他们拥有散列口令副本的状况一样糟糕。我们所创建的不是口令系统,而是一种延迟机制。
我们能做的一件事就是在错误登录尝试了几次(例如 5 次)后锁定帐户。然后,应该迫使用户与管理员或客户支持人员交涉,以使他们的帐户解锁。这种方案一个新的问题在于,在解锁用户被锁定的帐户时验证他们的身份很困难。您怎么知道这个人不是碰巧知道目标社会保障号或类似信息的攻击者呢?
最好的办法是让这个人提供真实的口令。问题很明显:您怎么能分辨出他是一个天生无法记住口令的人还是实施社会工程攻击的攻击者呢?超过了限制的次数后,攻击者当然会在电话中说:“我记不住口令!”。一种能稍微缓解这种情况的方式是在出现登录失败时进行记录。自动攻击可能在一两秒钟的时间内导致许多失败的尝试。另一件要做的事是将锁定帐户前的尝试次数设置在 50 左右。如果用户真是忘了口令,他不太会尝试 50 种不同的口令;一个更可行的方式是打电话给客户支持人员。因此,如果达到阈值 50,则很有可能是攻击,您应该明白用户能够提供真实的口令。
很明显,错误的登录计数器需要在每次发生有效登录时被复位。这样就引入了一种风险,即攻击者在每次有效用户登录前尝试 49 个口令(然后指望用户再提供另外 49 个猜测机会)。如果口令选择得好,这不是什么大问题。不过,假设用户选择的口令不那么好,那么该怎么做呢?我们建议长期跟踪错误登录尝试。每次全局计数器超过 200 时,就要求用户更改有问题的口令。
所有计数器信息都可以存储在口令文件未使用的字段中。
口令选择
到目前为止,我们谈到的所有问题都假设在人们选择口令时,所有可能的口令几率都是同等的。然而我们都知道事实不是这样。人们选取容易记住的事物。这样的事实就使口令的有效性大打折扣。有一些程序(例如 Crack)可以帮助攻击者聪明地猜出口令。当然,我们还有从有关“黑客”电影中得来的坐在那里尝试猜出某人的口令的画面,他们总能相当快地做到。在现实中,这样的人都使用 Crack 或类似的程序,而不是尝试毫无头绪地猜。不过,如果您对要尝试猜测其口令的人比较了解,猜测也可以相当有效。这样,通常不需要几次尝试就能猜出其它人的口令。
许多软件系统强迫用户提供满足基本质量标准的口令。用户输入口令后,软件检查口令的质量,如果口令有问题,通知用户,他必须选择另一个口令。
软件还可以为用户提供选择好口令的建议。这是个不错的主意,但如果建议的过程不是非常完美的话常常会事与愿违,因为如果为人们提供一个过程,他们往往会按照这个过程操作。这样,人们就会选取似乎经过精挑细选的口令,其实不然。例如,我们就曾看到过程序提供以下建议:
选择两个容易记住的词,将它们组合起来,在中间插入一个标点。例如:good!advice
该建议真的不是非常好。大多数口令破译程序,包括 Crack 本身,都会尝试这种模式,它们最终都能解译上述口令。让我们尝试更好一些的建议:
使用对您很重要的日期(可能是您母亲的生日),然后将它与一个标点和一些容易记住的文本(例如您母亲的姓名首字母)组合起来。例如 033156!glm
这个口令比 "good!advice" 要好。除了人们使用您的程序选择的口令看上去都非常相似以外,这可能是个不错的口令。Crack 程序将逐步适应检查使用这种技术构造起来的口令。到那时,情况将完全相反。
让我们看一些更好的建议:
选择您容易记住的一句话,例如著名的引语或歌词。使用每个词的第一个字母,保留其大小写,再使用任何标点。例如,可能选择引语 "I am Ozymandius, king of all kings!",然后使用口令:IaO,koak!
这个建议很容易照做,而且比上两种建议更难攻击。当然,有些人比较懒,可能窃用您使用的引语。您需要确保不让这种事发生。知道引语源的人所引用的引语,对于知道您所使用的建议的攻击者来说很可能猜得出来。例如,您可能从同一首诗,或同一个作者那里选择另一段引语。或者可能从另一首至少同样有名的诗中选择另一段引语,例如 "Two roads diverged in a wood"。攻击者可以创建一个可能的候选者的列表。他们还可能使用 Bartlet抯 Quotations 的全部内容,为每段引语生成匹配的口令,将这些口令添加到他们的口令字典中来进行尝试。他们还会对算法进行一些(假设 20 种)修改,然后再生成那些口令。
您不太可能不告诉用户选择好口令所使用的过程而意外地建议一个拙劣的口令;而只告诉用户为什么不喜欢他们的第一个选择。例如:
输入新口令:viega
不能接受:那是您的用户名。
输入新口令:john
不能接受:是个容易猜出的字。
输入新口令:redrum
不能接受:我还是能读出 Shining。
输入新口令:dk$
不能接受:口令太短。
这里最大的问题是幼稚的用户不一定知道如何选取更好的口令。我们曾看到一些聪明人(但是仍幼稚的用户)坐了 10 分钟尝试找出一个系统能接受的口令,最终还是灰心地放弃了。
将这两种技术结合起来比较合理。首先,让用户尝试一些口令,如果您不能接受,说明原因。几次失败后,提供一些建议。小心您所提供的建议。您需要从一组建议中进行选择,随机地提供一两条。
更多建议
有时,提供常规建议而没有口令示例确实比较好。以下是您需要采用的一些建议:
口令应该至少 8 个字符长。
不要害怕使用很长的口令。
避免与您所拥有的其它口令在任何方面有类似性的口令。
避免使用可以在字典、名称簿、地图等地方查到的口令。
考虑将数字和标点合并到口令中。
注:如果使用了一些公共字,请考虑使用数字和标点替换字中的字母。不过,不要使用“外形类似”的标点。例如,最好不要将 "cat" 改为 "c@t"、"ca+"、 '(@+" 或任何类似的字符。
掷骰子
口令选择的实施在安全性和可用性之间有取舍。可用性最强的系统是那些从不拒绝任何提出的口令(即使要猜出它简直太容易了)的系统。人们要生成好的口令有个非常好的办法,但它使用起来可能很困难。这种技术需要三个骰子。要生成口令的单一字母,滚动骰子,从左至右地读,然后在下面的图表中查找。要避免哪个是最左面的这种不明确性,执行以下操作会有帮助:将骰子在盒子中滚动,然后倾斜盒子直到所有骰子相互靠紧排成一行。
例如,假设开始掷骰子了,滚动出一个 4,一个 6 和一个 1。对于我们第一个字符,使用 "#"。如果滚动的结果在下面的图表中没有出现,必须再滚一次。这种情况平均每 10 掷就会发生至少一次。当口令看上去象个真正的词时,再次重新开始。
这种技术提供了给定长度的完全随机的口令分发。用户至少应该滚动 8 次(少于 53 位的安全性)。我们建议最少 10 个字母(大约 64 位)。在前一篇文章中我们提到过,20 次滚动应该能够提供用于任何目的的安全性了(大约 128 位)。
第一面  第二面 第三面 字符
1 或 2 1 1 a
1 或 2 1 2 b
1 或 2 1 3 c
1 或 2 1 4 d
1 或 2 1 5 e
1 或 2 1 6 f
1 或 2 2 1 g
1 或 2 2 2 h
1 或 2 2 3 i
1 或 2 2 4 j
1 或 2 2 5 k
1 或 2 2 6 l
1 或 2 3 1 m
1 或 2 3 2 n
1 或 2 3 3 o
1 或 2 3 4 p
1 或 2 3 5 q
1 或 2 3 6 r
1 或 2 4 1 s
1 或 2 4 2 t
1 或 2 4 3 u
1 或 2 4 4 v
1 或 2 4 5 w
1 或 2 4 6 x
1 或 2 5 1 y
1 或 2 5 2 z
1 或 2 5 3 A
1 或 2 5 4 B
1 或 2 5 5 C
1 或 2 5 6 D
1 或 2 6 1 E
1 或 2 6 2 F
1 或 2 6 3 G
1 或 2 6 4 H
1 或 2 6 5 I
1 或 2 6 6 J
3 或 4 1 1 K
3 或 4 1 2 L
3 或 4 1 3 M
3 或 4 1 4 N
3 或 4 1 5 O
3 或 4 1 6 P
3 或 4 2 1 Q
3 或 4 2 2 R
3 或 4 2 3 S
3 或 4 2 4 T
3 或 4 2 5 U
3 或 4 2 6 V
3 或 4 3 1 W
3 或 4 3 2 X
3 或 4 3 3 Y
3 或 4 3 4 Z
3 或 4 3 5 0
3 或 4 3 6 1
3 或 4 4 1 2
3 或 4 4 2 3
3 或 4 4 3 4
3 或 4 4 4 5
3 或 4 4 5 6
3 或 4 4 6 7
3 或 4 5 1 8
3 或 4 5 2 9
3 或 4 5 3 `
3 或 4 5 4 ~
3 或 4 5 5 !
3 或 4 5 6 @
3 或 4 6 1 #
3 或 4 6 2 $
3 或 4 6 3 %
3 或 4 6 4 ^
3 或 4 6 5 ?
3 或 4 6 6 *
5 或 6 1 1 (
5 或 6 1 2 )
5 或 6 1 3 _
5 或 6 1 4 -
5 或 6 1 5 +
5 或 6 1 6 =
5 或 6 2 1 {
5 或 6 2 2 [
5 或 6 2 3 }
5 或 6 2 4 ]
5 或 6 2 5 |
5 或 6 2 6 \
5 或 6 3 1 :
5 或 6 3 2 ;
5 或 6 3 3 ?
5 或 6 3 4 ?
5 或 6 3 5  
5 或 6 3 6 ,
5 或 6 4 1 >
5 或 6 4 2 .
5 或 6 4 3 ?
5 或 6 4 4 /
5 或 6 4 5 SPACE
5 或 6 4 6 TAB
5 或 6 5 或 6 任何数 再滚一次
这种技术的问题是对于用户来说困难了一些,他们不仅必须滚动许许多多的骰子,而且还必须跟踪产生的口令。
顺便说一句,有人建议永远不要写下任何口令,只记住它们。理由是,如果写下它,就可能有人发现并读取它。是的,确实有这种情况。不过,如果您不写下来,就必须选择容易记的东西。如果容易记住,象 Crack 这样的程序可能也就容易破解。我们宁可看到人们选择高质量的口令并将它们写下来,因为我们认为这种方法不太可能泄露它们。将口令表放在您的皮夹里并没什么错,只要您能管好您的皮夹,从不到处乱放该口令表。
存储大量帐户/口令对而不用担心丢失记录它们的纸的一个方法是使用“口令保险箱”,例如 Counterpane 提供的一个(请参阅参考资料),这是一个将口令在磁盘上加密的电子程序。要获取口令,只需要打开保险箱。当然,对保险箱的“组合”本身是个口令;用户必须记住至少一个口令,但这样就可以免去管理多个口令的负担了。这样的工具远比对多个帐户使用相同口令的方法好。
请注意,保险箱中的所有口令都不如解锁保险箱的口令有效,因为如果打开保险箱的话就能不费力地获得里面所有口令。因此,特别注意要对保险箱使用好的口令。
口令短语
口令短语就是口令。两者之间没有任何实质的不同,除了术语本身明显的含义:“口令”鼓励用户考虑短的悦耳的,而“口令短语”则旨在鼓励用户输入完整的短语。除了短语具有任意长度外,没有任何事限制口令成为短语。通常也不排除口令短语是一个单字。
使用短语而不使用字通常是个好主意,因为它们更难破解。不过,短语也能被猜出。象 Crack 这样的程序就能检查引语簿中的所有事物,包括带有不同的标点和大小写的那些。但如果从这样的书中选择一个相当长的短语并做三到四处更改 -- 例如字交换、字母交换、添加标点或除去字母 -- 就可能获得不会被破解的短语。
但“可能”不是个很强烈的字。据估计,书中旧的纯文本每个字有大约 5 位的熵。如果选择随机字的字符串会做得更好。如果有一个可以从中选择的,具有 8,192 个字的字典,并且选择每一个都是同样可能的,那么每个字就有 13 位的熵。如果从该字典中选择 10 个字,就不用担心口令通过蛮力被破译。
与口令很相似,可以通过滚动骰子创建高质量的口令短语。Diceware 主页(请参阅参考资料)有一个包含 7,776 个字的字典,您可以通过滚动骰子从中进行随机选择。下面是它的工作方法:一次滚动 5 个骰子,然后从左至右地读取它们。读出的值是个 5 位数,例如 62,142。在 Diceware 字列表中查找该数,给出口令短语的第一个字。使用 Diceware 选择的每个字提供大约 12.9 位的熵;不过,如果口令短语碰巧是个逻辑句子,或者它非常短,以至于可以通过蛮力打开,那么口令短语的熵就少一些。(Diceware 页面建议口令短语最少要有 5 个字,并建议用户抛出 13 个或 13 个以下字符的口令短语。这个建议很有道理。)
应用程序选择的口令
当然,让用户执行我们所建议的所有掷骰子的工作不是很合理。但您可以为他们掷骰子。唯一需要注意的是需要完全随机的数;使用 rand() 来从列表中选择随机字符或随机字并不能满足要求。下面是生成完全随机口令的函数。它使用我们在本专栏前一部分中介绍的随机库。
char *get_random_password(int numchars)
{
static char letters =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"~`!@#$%^&()_-+={[}]|\\:;\"?,>.?/";

char *s = malloc(numchars+1);
int i;
for(i=0;i
  
下面是以软件实现 Diceware 技术的代码。它通过从称为 wordlist.dat 的文件中进行选择来生成随机口令短语(请参阅参考资料)。
char *get_passphrase(int numwords, int ranchar)

  
该函数返回指定字数的随机口令短语。如果 randchar 不是 0,将从口令短语中随机选择一个字,并随机添加一个标点字符或数,这样就在短语中每个字提供的 13 位熵的基础上再增加 5.5 位的熵。
单击此处查看样本代码。
小结
虽然身份验证是计算机安全性中最简单的一个概念,但它也是最难做到的一个。今天,我们只触及表面。在今后的部分中,我们将讨论您可以在软件中使用的其它身份验证技术,例如公钥身份验证和生物统计身份验证。





欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/) Powered by Discuz! 7.2