Post-It的安全性


16

如您所知,黑客无处不在,他们想入侵一切。您被要求提出密码要求,这将阻止任何黑客。问题是,您的老板听说为LOC付费是邪恶的,他付给您$ 1800-$ 0.03 *每月插入的字符,使您写出可能可行的最简单的东西。因此,您必须使用少量字符(希望很小),否则就不用花钱了。同样,您的老板不在乎您将使用哪种语言。

良好密码的要求与上述文章类似,只是删除了基于字典的要求,以避免使解决方案依赖于外部文件,您不必检查是否重新排列了字母(很难理解其实际含义),最后一条规则被删除(3/4是什么?),它不检查旧密码。

从链接的文章中删除某些要求后的确切要求是:

  • 至少有8个字符!
  • 不能超过12个字符!
  • 有大小写字符!
  • 最多包含8个大写字母!
  • 最多包含8个小写字母!
  • 至少有2个字母!
  • 有一封领导信!
  • 至少有1位数字!
  • 不是您的用户名!
  • 不要将您的用户名倒退!
  • 不包含您的用户名!
  • 向后不包含您的用户名!
  • 最多有1对重复字符!
  • 没有3个出现次数相同字符的!
  • 不含克拉(^)
  • 没有空间
  • 不包含=
  • conatain
  • 不含 #
  • 不含 ,
  • conatain ;
  • 不含 ”
  • 不包含>
  • 不包含<
  • 不含 [
  • 不包含
  • 不含 )

此列表上的所有拼写错误均保留原样。

$ ./checkpass
Username: John
Password: L!]E2m69
OK.

$ ./checkpass
Username: John
Password: JohnnhoJ12
Nope.

$ ./checkpass
Username: JOE.smith
Password: JOE!smith123
OK.

最短的代码会赢钱(作为JPG文件发送)。它必须显示“用户名:”和“密码:”提示并提供准确的消息答复。


1
很好,在每日WTF文章+1 ;-)中看到了一场代码高尔夫挑战赛
ChristopheD

1
第一个示例应该失败(“具有大小写字符!”),不是吗?
霍华德

@Howard:这意味着密码中需要同时使用大写和小写字母。注意缺少单词“ not”。
Konrad Borowski

在某些字体中,第一个密码中的l是小写字母ell而不是数字不是很明显,因此我正在编辑用明确的小写字母替换它。
彼得·泰勒

@PeterTaylor啊,谢谢。实际上,我将其读为1(数字1)而不是ell。
霍华德

Answers:


8

Perl中,203 194 189 193个字符

这是我对Perl的看法:

print"Username: ";chop($u=<>);$n=reverse$u;print"Password: ";$_=<>;
say/^\pL.{7,11}$/*/\d/*/[A-Z]/*9>y/A-Z//&y/a-z//<9*/[a-z]/*
!/[" #,;->^&[|)]|(.)(.*\1.*\1|\1.*(.)\3)|\Q$u\E|\Q$n/?"OK.":"Nope."

正则表达式按顺序检查密码:

  • 以字母开头,具有八至十二个字符

  • 包含一个数字

  • 包含一个大写字母

  • 具有八个或更少的大写字母

  • 具有八个或更少的小写字母

  • 包含小写字母

  • 不包含任何禁止的标点符号,任何字符出现3次,双倍字符出现多次,用户名或用户名颠倒。

(感谢Peter Taylor指出了189个字符的版本中的一个错误。)


弄清楚了如何在ideone上运行use v5.10;它,但失败了我的“正则表达式正确逃脱”测试用例。参见ideone.com/QKFnZ
Peter Taylor

@PeterTaylor:我不了解Ruby,但是在Perl中可以解决\Q$u\E|\Q$n\E如果可以将这部分移到最后,可以跳过最后一个)。
Konrad Borowski 2012年

OTOH我认为可以通过将重复项合并为一个字符来保存(.)(.*\1.*\1|\1.*(.)\3)(未经测试-我不会尝试使用ideone编写完整的测试电池脚本)。
彼得·泰勒

5

Ruby,270个字符

$><<"Username: ";u=gets.chop
$><<"Password: ";gets
puts ('^.{8,12}$+\p{Lower}+\p{Upper}+^(\p{Alpha}.*){2}+\d+(\p{Lower}.*){9}+(\p{Upper}.*){9}+(.)\1.*(.)\2+(.).*\1.*\1+[ ^=&#,;"<>\[|)]+'+u+?++u.reverse).split(?+).map{|r|/#{r}/=~$_??A:?B}*""=="AAAAABBBBBBB"?"OK.":"Nope."

ruby实现基于十二个正则表达式。每个表达式都是正向匹配(前五个)或负向匹配(后七个)。作为限制,用户名只能包含字母或数字。

正则表达式匹配:

  • /^.{8,12}$/:至少包含8个字符!不得超过12个字符!
  • /\p{Lower}//\p{Upper}/:具有大写和小写字符!
  • /^(\p{Alpha}.*){2}/:至少要有2个字母!,要有前导字母!
  • /\d/:至少有1位数字!

负正则表达式匹配:

  • /(\p{Lower}.*){9}/:最多包含8个小写字母!
  • /(\p{Upper}.*){9}/:最多包含8个大写字母!
  • /(.)\1.*(.)\2/:最多有1对重复字符!
  • /(.).*\1.*\1/:没有3个相同角色的事件!
  • /[ ^=&#,;"<>\[|)]/:不包含脱字号,空格,=,&,#、、、;,“,>,<,[,|,)
  • /#{u}/:不是您的用户名!,不包含您的用户名!
  • /#{u.reverse}/:不要将您的用户名倒退!,不要包含您的用户名倒退!

这不会逃逸用户名,因此可以拒绝完全有效的密码。测试用例在ideone.com/bPpeo
彼得·泰勒

@PeterTaylor这就是为什么我在回答中指出了对用户名的限制。
霍华德

1

Python 3,291个字节/字符

from re import*
n,p=map(input,["Username: ","Password: "])
c,U,L=lambda x:len(split("[%s]"%x,p)),"A-Z","a-z"
print(["OK.","Nope."][any([8>len(p)>12,2>c(U)>9,2>c(L)>9,3>c(U+L),match(U+L,p),2>c("0-9"),n in p,n[::-1]in p,any(c(x)>3 for x in p),len(findall("(.)\\1",p))>1,c(' ^=&#,;"><[|)')>1])])

格式和注释更准确:

# import all elements from the regular expression module
from re import *

# Get the two lines of user input (username `n`, password `p`):
n, p = map(input, ["Username: ","Password: "])

# Assign some internally useful shortcuts (uppercase letters `U`, lowercase letters `L`):
# `c(x)` counts the occurrences of pattern `x` in the password `p` plus 1
c, U, L = lambda x: len(split("[%s]" % x, p)), "A-Z", "a-z"

# Print the test result: `"OK."` if the `any(...)` function returned `False`, else `"Nope."`.
# The `any(...)` combines the result of all enclosed checks and returns `True` if at least
# one of the checks failed (returned `True`).
print(["OK.", "Nope."][any([                                # vvv--- CHECKS: ---vvv
                             8>len(p)>12,                   # password length 8-12
                             2>c(U)>9,                      # 1-8 uppercase letters
                             2>c(L)>9,                      # 1-8 lowercase letters
                             3>c(U+L),                      # at least 2 letters
                             match(U+L,p),                  # starts with a letter
                             2>c("0-9"),                    # at least 1 digit
                             n in p,                        # username is not (in) the pw.
                             n[::-1]in p,                   # reversed name not (in) the pw.
                             any(c(x)>3 for x in p),        # at most 3 same characters
                             len(findall("(.)\\1",p))>1,    # at most 1 pair (e.g. "AA")
                             c(' ^=&#,;"><[|)')>1])         # does not contain special char.
                           ])

您可以在ideone.com上找到此解决方案,但是输出看起来有点难看,因为它没有显示预定义的输入,甚至没有换行符。另外,用户名和密码的组合"JOE.smith"- "JOE!smith123"当前作为固定输入数据输入。
我添加了所有检查的细目作为调试输出。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.