Pwned Passwords API를 사용하는 쉬운 Ruby 방법입니다.
API 문서 | GitHub 저장소
Troy Hunt의 Pwned Passwords API를 사용하면 대규모 데이터 유출에서 비밀번호가 발견되었는지 확인할 수 있습니다.
Pwned
는 Pwned Passwords API의 k-익명성 모델을 사용하여 전체 비밀번호를 서비스에 전송하지 않고 API에 대해 비밀번호를 테스트하는 Ruby 라이브러리입니다.
이 API의 데이터는 Have I been pwned?에서 제공됩니다. API를 사용하기 전에 API의 허용되는 용도와 라이선스를 확인하세요.
다음은 Ruby 애플리케이션에서 이 gem을 사용하여 사용자의 비밀번호를 더 좋게 만드는 방법에 대해 제가 쓴 블로그 게시물입니다.
애플리케이션의 Gemfile에 다음 줄을 추가하세요.
gem 'pwned'
그런 다음 다음을 실행합니다.
$ bundle
또는 다음과 같이 직접 설치하십시오.
$ gem install pwned
이 gem을 사용할 수 있는 몇 가지 방법이 있습니다:
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
대부분의 경우 비밀번호가 이전에 생성되었는지 여부에만 관심이 있습니다. 단순화된 접근자를 사용하여 비밀번호가 pwned되었는지 여부 또는 pwned된 횟수를 확인할 수 있습니다.
Pwned . pwned? ( "password" )
#=> true
Pwned . pwned_count ( "password" )
#=> 3303003
API에 요청할 때 Net::HTTP.start
와 함께 사용할 HTTP 요청 옵션을 설정할 수 있습니다. 이러한 옵션은 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 프록시를 처리하는 것과 같은 방식입니다. Ruby가 환경에서 프록시를 감지하는 방법에 대한 자세한 내용은 URI::Generic#find_proxy
참조하세요.
# Set in the environment
ENV [ "http_proxy" ] = "https://username:[email protected]:12345"
# Will use the above proxy
password = Pwned :: Password . new ( "password" )
:proxy
옵션을 사용하여 사용자 정의 HTTP 프록시를 지정할 수 있습니다:
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
유효성 검사기 매개변수로 변경할 수 있습니다:
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 프록시를 처리하는 것과 같은 방식입니다. Ruby가 환경에서 프록시를 감지하는 방법에 대한 자세한 내용은 URI::Generic#find_proxy
참조하세요.
# Set in the environment
ENV [ "http_proxy" ] = "https://username:[email protected]:12345"
validates :password , not_pwned : true
:proxy
키를 사용하여 사용자 정의 HTTP 프록시를 지정할 수 있습니다.
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를 사용하고 있다면 이제 이 gem으로 구동되는 devise-pwned_password 확장을 사용하는 것이 좋습니다.
Rodauth를 사용하고 있다면 이 gem으로 구동되는 Rodauth-pwned 기능을 사용할 수 있습니다.
gem은 비밀번호 확인을 위한 명령줄 유틸리티를 제공합니다. 다음과 같이 터미널 애플리케이션에서 호출할 수 있습니다.
$ pwned password
Pwned !
The password has been found in public breaches 3645804 times.
확인 중인 비밀번호를 표시하지 않으려면 다음으로 전화하세요.
$ pwned --secret
비밀번호를 묻는 메시지가 표시되지만 표시되지는 않습니다.
불필요한 네트워크 요청을 줄이기 위해 unpwn 프로젝트는 상위 100만 개의 비밀번호 목록을 사용하여 비밀번호를 확인합니다. 비밀번호가 상위 100만 개에 포함되지 않은 경우에만 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
에서 버전 번호를 업데이트한 다음, 버전에 대한 git 태그를 생성하고 git 커밋 및 태그를 푸시한 다음 .gem
파일을 rubygems.org에 푸시하는 bundle exec rake release
실행하세요.
버그 보고서 및 끌어오기 요청은 GitHub(https://github.com/philnash/pwned)에서 환영합니다. 이 프로젝트는 협업을 위한 안전하고 환영받는 공간이 되도록 의도되었으며 기여자는 기여자 규약 행동 강령을 준수해야 합니다.
이 gem은 MIT 라이선스 조건에 따라 오픈 소스로 제공됩니다.
Pwned 프로젝트의 코드베이스, 이슈 트래커, 채팅방 및 메일링 리스트에서 상호 작용하는 모든 사람은 행동 강령을 따라야 합니다.