ความปลอดภัยโดย 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

@Howard: หมายความว่าต้องใช้ตัวอักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็กในรหัสผ่าน สังเกตเห็นการขาดคำว่า "ไม่"
Konrad Borowski

มันไม่ชัดเจนในบางฟอนต์ที่ l ในรหัสผ่านแรกนั้นเป็นอักษรตัวพิมพ์เล็กและไม่ใช่หมายเลขหนึ่งดังนั้นฉันจึงแก้ไขเพื่อแทนที่ด้วยอักษรตัวพิมพ์เล็กที่ชัดเจน
Peter Taylor

@PeterTaylor อ่าขอบคุณ แน่นอนฉันอ่านมันเป็น1 (หลักหนึ่ง) แทน ell
Howard

คำตอบ:


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."

regexes ตรวจสอบตามลำดับรหัสผ่าน:

  • เริ่มต้นด้วยตัวอักษรมีแปดถึงสิบสองตัวอักษร

  • มีตัวเลข

  • มีตัวอักษรตัวพิมพ์ใหญ่

  • มีตัวอักษรตัวพิมพ์ใหญ่แปดตัวหรือน้อยกว่า

  • มีตัวอักษรพิมพ์เล็กแปดหรือน้อยกว่า

  • มีตัวอักษรตัวเล็ก

  • ไม่มีเครื่องหมายวรรคตอนที่ต้องห้ามใด ๆ เกิดขึ้นสามตัวอักขระใด ๆ เกิดขึ้นมากกว่าหนึ่งครั้งของตัวละครสองเท่าชื่อผู้ใช้หรือชื่อผู้ใช้กลับรายการ

(ขอบคุณ Peter Taylor ที่ชี้ให้เห็นข้อผิดพลาดในรุ่น 189-char)


คิดออกว่าจะใช้งานบน ideone ด้วยuse v5.10;และมันล้มเหลวกรณีทดสอบ "จะ regexes หนีอย่างถูกต้อง" ของฉัน ดูideone.com/QKFnZ
Peter Taylor

@ PeterTaylor: ฉันไม่รู้เกี่ยวกับ Ruby แต่ในการแก้ไข Perl จะเป็น\Q$u\E|\Q$n(สุดท้าย\Eสามารถข้ามถ้าส่วนนี้จะถูกย้ายไปยังจุดสิ้นสุด)
Konrad Borowski

OTOH ฉันคิดว่าตัวละครตัวหนึ่งสามารถบันทึกได้โดยการรวมการทำซ้ำเป็น(.)(.*\1.*\1|\1.*(.)\3)(ไม่ผ่านการทดสอบ - ฉันจะไม่ลองสคริปต์ทดสอบแบตเตอรี่เต็มรูปแบบด้วย ideone)
Peter Taylor

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."

การติดตั้งทับทิมสร้างขึ้นบนนิพจน์ปกติสิบสองนิพจน์ แต่ละนิพจน์เป็นทั้งคู่ที่เป็นบวก (ห้ารายการแรก) หรือลบหนึ่งรายการ (เจ็ดหลัง) ตามข้อ จำกัด ชื่อผู้ใช้อาจมีตัวอักษรหรือตัวเลขเท่านั้น

การจับคู่นิพจน์ปกติที่เป็นบวก:

  • /^.{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
Peter Taylor

@PeterTaylor นั่นเป็นเหตุผลที่ฉันบันทึกข้อ จำกัด สำหรับชื่อผู้ใช้ในคำตอบของฉัน
Howard

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"ปัจจุบันถูกป้อนเป็นข้อมูลป้อนเข้าคงที่
ฉันได้เพิ่มการแยกย่อยของเช็คทั้งหมดเป็นเอาท์พุทดีบั๊ก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.