วิธี Ruby ที่ง่ายดายในการใช้ Pwned Passwords API
เอกสาร API | พื้นที่เก็บข้อมูล GitHub
Pwned Passwords API ของ Troy Hunt ช่วยให้คุณตรวจสอบว่ามีการพบรหัสผ่านในการละเมิดข้อมูลขนาดใหญ่หรือไม่
Pwned
เป็นไลบรารี Ruby ที่ใช้โมเดล k-Anonymity ของ Pwned Passwords API เพื่อทดสอบรหัสผ่านกับ API โดยไม่ต้องส่งรหัสผ่านทั้งหมดไปยังบริการ
ข้อมูลจาก API นี้จัดทำโดย Have I been pwned? ก่อนที่จะใช้ API โปรดตรวจสอบการใช้งานและใบอนุญาตที่ยอมรับได้ของ API
นี่คือโพสต์บนบล็อกที่ฉันเขียนเกี่ยวกับวิธีใช้อัญมณีนี้ในแอปพลิเคชัน Ruby ของคุณเพื่อทำให้รหัสผ่านของผู้ใช้ของคุณดีขึ้น
เพิ่มบรรทัดนี้ลงใน Gemfile ของแอปพลิเคชันของคุณ:
gem 'pwned'
แล้วดำเนินการ:
$ bundle
หรือติดตั้งด้วยตัวเองเป็น:
$ gem install pwned
คุณสามารถใช้อัญมณีนี้ได้หลายวิธี:
หากต้องการทดสอบรหัสผ่านกับ API ให้สร้างอินสแตนซ์ของวัตถุ Pwned::Password
แล้วถามว่าเป็น pwned?
-
password = Pwned :: Password . new ( "password" )
password . pwned?
#=> true
password . pwned_count
#=> 3303003
คุณยังสามารถตรวจสอบได้ว่ารหัสผ่านปรากฏในชุดข้อมูลกี่ครั้ง
password = Pwned :: Password . new ( "password" )
password . pwned_count
#=> 3303003
เนื่องจากคุณมีแนวโน้มที่จะใช้สิ่งนี้เป็นส่วนหนึ่งของขั้นตอนการลงชื่อสมัครใช้ ขอแนะนำให้คุณแก้ไขข้อผิดพลาด ดังนั้นหากบริการล่ม เส้นทางผู้ใช้ของคุณจะไม่ถูกรบกวน
begin
password = Pwned :: Password . new ( "password" )
password . pwned?
rescue Pwned :: Error => e
# Ummm... don't worry about it, I guess?
end
โดยส่วนใหญ่แล้วคุณจะสนใจเฉพาะว่ารหัสผ่านนั้นเคยถูกใส่ไว้ก่อนหรือไม่เท่านั้น คุณสามารถใช้ตัวเข้าถึงแบบง่ายเพื่อตรวจสอบว่ารหัสผ่านถูก pw แล้วหรือกี่ครั้ง:
Pwned . pwned? ( "password" )
#=> true
Pwned . pwned_count ( "password" )
#=> 3303003
คุณสามารถตั้งค่าตัวเลือกคำขอ HTTP เพื่อใช้กับ Net::HTTP.start
เมื่อทำการร้องขอไปยัง API ตัวเลือกเหล่านี้ได้รับการบันทึกไว้ในเอกสาร Net::HTTP.start
คุณสามารถส่งตัวเลือกไปยังตัวสร้าง:
password = Pwned :: Password . new ( "password" , read_timeout : 10 )
คุณยังสามารถระบุค่าเริ่มต้นสากลได้:
Pwned . default_request_options = { read_timeout : 10 }
ตัวเลือก :headers
กำหนดส่วนหัว HTTP ส่วนหัวเหล่านี้ต้องเป็นคีย์สตริง
password = Pwned :: Password . new ( "password" , headers : {
'User-Agent' => 'Super fun new user agent'
} )
คุณสามารถตั้งค่าพร็อกซี HTTP ได้โดยใช้ตัวแปรสภาพแวดล้อม http_proxy
หรือ HTTP_PROXY
นี่เป็นวิธีเดียวกับที่ Net::HTTP
จัดการพร็อกซี HTTP หากไม่มีการระบุตัวเลือกพร็อกซี ดู URI::Generic#find_proxy
สำหรับรายละเอียดทั้งหมดเกี่ยวกับวิธีที่ Ruby ตรวจจับพร็อกซีจากสภาพแวดล้อม
# Set in the environment
ENV [ "http_proxy" ] = "https://username:[email protected]:12345"
# Will use the above proxy
password = Pwned :: Password . new ( "password" )
คุณสามารถระบุพร็อกซี HTTP แบบกำหนดเองด้วยตัวเลือก :proxy
:
password = Pwned :: Password . new (
"password" ,
proxy : "https://username:[email protected]:12345"
)
หากคุณไม่ต้องการตั้งค่าพร็อกซีและคุณไม่ต้องการให้พร็อกซีอนุมานจากสภาพแวดล้อม ให้ตั้งค่าคีย์ :ignore_env_proxy
:
password = Pwned :: Password . new ( "password" , ignore_env_proxy : true )
มีเครื่องมือตรวจสอบแบบกำหนดเองสำหรับโมเดล ActiveRecord ของคุณ:
class User < ApplicationRecord
validates :password , not_pwned : true
# or
validates :password , not_pwned : { message : "has been pwned %{count} times" }
end
คุณสามารถเปลี่ยนข้อความแสดงข้อผิดพลาดได้โดยใช้ I18n (ใช้ %{count}
เพื่อประมาณจำนวนครั้งที่เห็นรหัสผ่านในการละเมิดข้อมูล):
en :
errors :
messages :
not_pwned : has been pwned %{count} times
pwned_error : might be pwned
หากคุณพอใจกับรหัสผ่านที่ปรากฏหลายครั้งก่อนที่คุณจะตัดสินใจว่าไม่ถูกต้อง คุณสามารถกำหนดเกณฑ์ได้ เครื่องมือตรวจสอบจะตรวจสอบว่า pwned_count
มากกว่าเกณฑ์หรือไม่
class User < ApplicationRecord
# The record is marked as valid if the password has been used once in the breached data
validates :password , not_pwned : { threshold : 1 }
end
ตามค่าเริ่มต้น บันทึกจะถือว่าถูกต้องเมื่อเราไม่สามารถเข้าถึงเซิร์ฟเวอร์ haveibeenpwned.com สิ่งนี้สามารถเปลี่ยนแปลงได้ด้วยพารามิเตอร์ :on_error
validator:
class User < ApplicationRecord
# The record is marked as valid on network errors.
validates :password , not_pwned : true
validates :password , not_pwned : { on_error : :valid }
# The record is marked as invalid on network errors
# (error message "could not be verified against the past data breaches".)
validates :password , not_pwned : { on_error : :invalid }
# The record is marked as invalid on network errors with custom error.
validates :password , not_pwned : { on_error : :invalid , error_message : "might be pwned" }
# We will raise an error on network errors.
# This means that `record.valid?` will raise `Pwned::Error`.
# Not recommended to use in production.
validates :password , not_pwned : { on_error : :raise_error }
# Call custom proc on error. For example, capture errors in Sentry,
# but do not mark the record as invalid.
validates :password , not_pwned : {
on_error : -> ( record , error ) { Raven . capture_exception ( error ) }
}
end
คุณสามารถกำหนดค่าคำขอเครือข่ายที่สร้างจากเครื่องมือตรวจสอบความถูกต้องได้โดยใช้ :request_options
(ดู Net::HTTP.start สำหรับรายการตัวเลือกที่มี)
validates :password , not_pwned : {
request_options : {
read_timeout : 5 ,
open_timeout : 1
}
}
ตัวเลือกเหล่านี้จะแทนที่ตัวเลือกเริ่มต้นที่กำหนดไว้ทั่วโลก (ดูด้านบน)
นอกจากตัวเลือกเหล่านี้แล้ว คุณยังสามารถตั้งค่าต่อไปนี้ได้ด้วย:
ส่วนหัว HTTP สามารถระบุได้ด้วยคีย์ :headers
(เช่น "User-Agent"
)
validates :password , not_pwned : {
request_options : {
headers : { "User-Agent" => "Super fun user agent" }
}
}
คุณสามารถตั้งค่าพร็อกซี HTTP ได้โดยใช้ตัวแปรสภาพแวดล้อม http_proxy
หรือ HTTP_PROXY
นี่เป็นวิธีเดียวกับที่ Net::HTTP
จัดการพร็อกซี HTTP หากไม่มีการระบุตัวเลือกพร็อกซี ดู URI::Generic#find_proxy
สำหรับรายละเอียดทั้งหมดเกี่ยวกับวิธีที่ Ruby ตรวจจับพร็อกซีจากสภาพแวดล้อม
# Set in the environment
ENV [ "http_proxy" ] = "https://username:[email protected]:12345"
validates :password , not_pwned : true
คุณสามารถระบุพร็อกซี HTTP แบบกำหนดเองได้ด้วย :proxy
key:
validates :password , not_pwned : {
request_options : {
proxy : "https://username:[email protected]:12345"
}
}
หากคุณไม่ต้องการตั้งค่าพร็อกซีและคุณไม่ต้องการให้พร็อกซีอนุมานจากสภาพแวดล้อม ให้ตั้งค่าคีย์ :ignore_env_proxy
:
validates :password , not_pwned : {
request_options : {
ignore_env_proxy : true
}
}
คุณอาจมีกรณีการใช้งานสำหรับการแฮชรหัสผ่านล่วงหน้า จากนั้นทำการเรียกไปยัง Pwned Passwords API ในภายหลัง (เช่น หากคุณต้องการจัดคิวงานโดยไม่จัดเก็บรหัสผ่านข้อความธรรมดา) ในการดำเนินการนี้ คุณสามารถแฮชรหัสผ่านด้วยวิธี Pwned.hash_password
จากนั้นเริ่มต้นคลาส Pwned::HashedPassword
ด้วยแฮช เช่นนี้
hashed_password = Pwned . hash_password ( password )
# some time later
Pwned :: HashedPassword . new ( hashed_password , request_options ) . pwned?
ตัวสร้าง Pwned::HashedPassword
ใช้ตัวเลือกเดียวกันกับตัวสร้าง Pwned::Password
ปกติ
หากคุณใช้ Devise ฉันขอแนะนำให้คุณใช้ส่วนขยาย devise-pwned_password ซึ่งขณะนี้ขับเคลื่อนโดย gem นี้
หากคุณใช้ Rodauth คุณสามารถใช้ฟีเจอร์ rodauth-pwned ซึ่งขับเคลื่อนโดย gem นี้
อัญมณีจัดเตรียมยูทิลิตี้บรรทัดคำสั่งสำหรับตรวจสอบรหัสผ่าน คุณสามารถเรียกมันได้จากแอปพลิเคชันเทอร์มินัลของคุณดังนี้:
$ pwned password
Pwned !
The password has been found in public breaches 3645804 times.
หากคุณไม่ต้องการให้รหัสผ่านที่คุณกำลังตรวจสอบปรากฏ โปรดโทร:
$ pwned --secret
คุณจะได้รับแจ้งให้ใส่รหัสผ่าน แต่จะไม่แสดงขึ้น
เพื่อลดคำขอเครือข่ายที่ไม่จำเป็น โปรเจ็กต์ unpwn จะใช้รายการรหัสผ่านหนึ่งล้านอันดับแรกในการตรวจสอบรหัสผ่าน เฉพาะในกรณีที่รหัสผ่านไม่รวมอยู่ในล้านอันดับแรกเท่านั้น ระบบจะตรวจสอบกับ Pwned Passwords API
@daz แบ่งปันตัวอย่างที่ยอดเยี่ยมของการใช้อัญมณีนี้เพื่อแสดงจำนวนครั้งที่มีการใช้ตัวเลขของ Pi เป็นรหัสผ่านและรั่วไหล
require 'pwned'
PI = '3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111'
for n in 1 .. 40
password = Pwned :: Password . new PI [ 0 .. ( n + 1 ) ]
str = [ n . to_s . rjust ( 2 ) ]
str << ( password . pwned? ? '?' : '?' )
str << password . pwned_count . to_s . rjust ( 4 )
str << password . password
puts str . join ' '
end
ผลลัพธ์อาจทำให้คุณประหลาดใจหรือไม่ก็ได้
1 ? 16 3.1
2 ? 238 3.14
3 ? 34 3.141
4 ? 1345 3.1415
5 ? 2552 3.14159
6 ? 791 3.141592
7 ? 9582 3.1415926
8 ? 1591 3.14159265
9 ? 637 3.141592653
10 ? 873 3.1415926535
11 ? 137 3.14159265358
12 ? 103 3.141592653589
13 ? 65 3.1415926535897
14 ? 201 3.14159265358979
15 ? 41 3.141592653589793
16 ? 57 3.1415926535897932
17 ? 28 3.14159265358979323
18 ? 29 3.141592653589793238
19 ? 1 3.1415926535897932384
20 ? 7 3.14159265358979323846
21 ? 5 3.141592653589793238462
22 ? 2 3.1415926535897932384626
23 ? 2 3.14159265358979323846264
24 ? 0 3.141592653589793238462643
25 ? 3 3.1415926535897932384626433
26 ? 0 3.14159265358979323846264338
27 ? 0 3.141592653589793238462643383
28 ? 0 3.1415926535897932384626433832
29 ? 0 3.14159265358979323846264338327
30 ? 0 3.141592653589793238462643383279
31 ? 0 3.1415926535897932384626433832795
32 ? 0 3.14159265358979323846264338327950
33 ? 0 3.141592653589793238462643383279502
34 ? 0 3.1415926535897932384626433832795028
35 ? 0 3.14159265358979323846264338327950288
36 ? 0 3.141592653589793238462643383279502884
37 ? 0 3.1415926535897932384626433832795028841
38 ? 0 3.14159265358979323846264338327950288419
39 ? 0 3.141592653589793238462643383279502884197
40 ? 0 3.1415926535897932384626433832795028841971
หลังจากตรวจสอบพื้นที่เก็บข้อมูลแล้ว ให้รัน bin/setup
เพื่อติดตั้งการขึ้นต่อกัน จากนั้นรัน rake spec
เพื่อรันการทดสอบ คุณยังสามารถเรียกใช้ bin/console
เพื่อรับข้อความโต้ตอบที่จะช่วยให้คุณสามารถทดลองได้
หากต้องการติดตั้ง gem นี้ลงในเครื่องของคุณ ให้รัน bundle exec rake install
หากต้องการออกเวอร์ชันใหม่ ให้อัปเดตหมายเลขเวอร์ชันใน version.rb
จากนั้นเรียกใช้ bundle exec rake release
ซึ่งจะสร้างแท็ก git สำหรับเวอร์ชัน กด git commits และแท็ก แล้วส่งไฟล์ .gem
ไปที่ rubygems.org
รายงานข้อผิดพลาดและคำขอดึงยินดีต้อนรับบน GitHub ที่ https://github.com/philnash/pwned โครงการนี้มีวัตถุประสงค์เพื่อเป็นพื้นที่ที่ปลอดภัยและเป็นมิตรสำหรับการทำงานร่วมกัน และผู้มีส่วนร่วมจะต้องปฏิบัติตามจรรยาบรรณของผู้ร่วมให้ข้อมูล
อัญมณีนี้มีให้ใช้งานในรูปแบบโอเพ่นซอร์สภายใต้เงื่อนไขของใบอนุญาต MIT
ทุกคนที่โต้ตอบในโค้ดเบส เครื่องมือติดตามปัญหา ห้องสนทนา และรายชื่ออีเมลของ Pwned จะต้องปฏิบัติตามหลักจรรยาบรรณ