Простой Ruby-способ использования API Pwned Passwords.
Документация по API | Репозиторий GitHub
API Pwned Passwords Троя Ханта позволяет вам проверить, был ли найден пароль в результате какой-либо серьезной утечки данных.
Pwned
— это библиотека Ruby, позволяющая использовать модель k-Anonymity API Pwned Passwords для проверки пароля на соответствие API без отправки всего пароля в службу.
Данные из этого API предоставлены Have I be 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
В большинстве случаев вас волнует только то, был ли пароль введен ранее или нет. Вы можете использовать упрощенные средства доступа, чтобы проверить, был ли взломан пароль или сколько раз он был взломан:
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
:
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
:
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
}
}
У вас может быть вариант использования предварительного хеширования пароля, а затем последующего вызова API Pwned Passwords (например, если вы хотите поставить задание в очередь без сохранения пароля в виде открытого текста). Для этого вы можете хешировать пароль с помощью метода 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, которое теперь поддерживается этим драгоценным камнем.
Если вы используете Rodauth, вы можете использовать функцию Rodauth, основанную на этом драгоценном камне.
Гем предоставляет утилиту командной строки для проверки паролей. Вы можете вызвать его из вашего терминального приложения следующим образом:
$ pwned password
Pwned !
The password has been found in public breaches 3645804 times.
Если вы не хотите, чтобы пароль, который вы проверяете, был виден, позвоните:
$ pwned --secret
Вам будет предложено ввести пароль, но он не будет отображаться.
Чтобы сократить количество ненужных сетевых запросов, проект unpwn использует список из миллиона самых популярных паролей для проверки паролей. Только если пароль не включен в верхний миллион, он затем проверяется с помощью API Pwned Passwords.
@daz поделился фантастическим примером использования этого драгоценного камня, чтобы показать, сколько раз цифры Пи использовались в качестве паролей и утекли.
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
для получения интерактивной подсказки, которая позволит вам поэкспериментировать.
Чтобы установить этот драгоценный камень на свой локальный компьютер, запустите bundle exec rake install
. Чтобы выпустить новую версию, обновите номер версии в version.rb
, а затем запустите bundle exec rake release
, который создаст тег git для этой версии, отправит git коммиты и теги и отправит файл .gem
на сайт Rubygems.org.
Отчеты об ошибках и запросы на включение приветствуются на GitHub по адресу https://github.com/philnash/pwned. Этот проект призван стать безопасным и гостеприимным пространством для сотрудничества, и ожидается, что участники будут соблюдать Кодекс поведения участников.
Гем доступен с открытым исходным кодом в соответствии с условиями лицензии MIT.
Ожидается, что все, кто взаимодействует с кодовыми базами проекта Pwned, системами отслеживания проблем, чатами и списками рассылки, будут следовать кодексу поведения.