对数字密码进行排名的算法?

时间:2015-03-19 15:42:12

标签: ruby algorithm user-interface mobile passwords

我正在学习一个(移动)应用,我需要获取用户PIN码: 一个6/8密码的数字“密码”,输入类似这样的UI:

passcode mokup

因此,在注册步骤中,用户配置他的一个密码(因为它将是一个密码)。

假设密码必须具有固定大小(例如8个密码:********)

我的问题与验证/检查用户选择的数字的可能算法有关,在重复密码或标准密码模式(1234567800001111)的情况下给出不良排名,易于预测被恶意破解者......

对这种算法有什么想法吗?

在第一眼看来,算法可能会阻止(排名不好)包含重复密码的密码,如:

00117788
88886611 

或“通常”上升/下降模式为:

12345678
98765432

或者与个人相关的数字模式,例如在我的情况下,我出生于1963年9月2日,所以使用密码可能是一个坏主意:

02091963

相反,在我看来“好”的序列可以是这样的例子:

18745098 
90574808
07629301

附带问题:您是否认为使用8个密码的数字密码作为验证付款交易的“密码”可以作为可接受的解决方案?

顺便说一下,我是用Ruby编写的。

感谢您的耐心等待!

乔治

1 个答案:

答案 0 :(得分:3)

前两种情况:

字符串中重复的连续字符数:

str = "00117788"
str.chars.each_cons(2).select {|a,b| a == b}.count
#=> 4

或者@CarySwoveland指出这将有相同的结果

str.size - str.squeeze.size
#=> 4

递增字符数

str = "12345678"
str.chars.map(&:to_i).each_slice(2).select {|a,b| (a + 1) == b || (a - 1) == b }.count
#=> 4
#note this will also return 4 for "12563478"
# you could also use str.chars.map(&:to_i).each_cons(2).select {|a,b| (a + 1) == b || (a - 1) == b }.count
# This will return 7 for "12345678" and still return 4 for "12563478"

您可以将上述2与

结合使用
str = "00117788"
str.chars.map(&:to_i).each_cons(2).select {|a,b| (a + 1) == b || (a - 1) == b || a == b }.count
#=> 6

至于“个人”问题,如果您有出生日,那么这样简单的事情应该有效:

require 'date'
birth_day = Date.new(1963,9,2)
str = "02091963"
str == birth_day.strftime("%d%m%Y")
#=> true

虽然对于最后一个,我建议比较多种格式,例如%Y%m%d%m%d%Y等您甚至可以执行类似

的操作
str.chars.sort == birth_day.strftime("%d%m%Y").chars.sort
#=> true

确保他们不只是以某种混乱的格式使用这些数字。

希望这会让你开始,因为我不知道你的“好”和“坏”的阈值是什么,这些只是检查值的建议。虽然看起来“好”的定义应该不是“坏”。有点像有效性检查。

如果我建议得分< 4使用方法1和2(或组合方法)&amp;&amp;不是各种各样的出生日数可能就足够了,例如。

def tester(str,birth_date)
  return false if ![6,8].include?(str.size)
  b_day = birth_date.strftime("%Y%m%d").chars.sort
  str.chars.map(&:to_i).each_cons(2).select  do |a,b| 
    (a + 1) == b || 
    (a - 1) == b || 
    a == b 
  end.count < 4 && b_day != str.chars.sort
end
tester("00112233",Date.new(1963,9,2))
#=> false
tester("18745098",Date.new(1963,9,2))
#=> true

似乎适用于您的示例

arry = ["00117788","88886611","12345678","98765432","02091963","18745098","90574808","07629301"]
Hash[arry.map{|v| [v,tester(v,Date.new(1963,9,2))]}]
#=>=> {"00117788"=>false, "88886611"=>false, 
       "12345678"=>false, "98765432"=>false, 
       "02091963"=>false, "18745098"=>true, 
       "90574808"=>true, "07629301"=>true}