短いパスワードのハッシュ反復回数を増やすことにより、パスワードのセキュリティを向上させる可能性を検討します。
この方法で私が目にするセキュリティ上の利点は次のとおりです。
これは優れたセキュリティ対策ですか?
これは、正式な名前ですでに確立された慣行ですか?
私がこれを使用したいシステムには、すでにパスワードハッシャーのプラグインアーキテクチャがあり、パスワードポリシーを適用するための集中的な方法がなく、パスワードポリシーを適用する権限がない場合があります。
このアプローチの考えられる欠点を検討しましたが、考えられるそれぞれの欠点について、それが問題ではない理由を見つけました。
パスワードの長さの潜在的なリーク:パスワードデータベースには、より長いパスワードに使用される最小反復回数のみが保存され、有効な反復回数はその場で計算されるため、データベースは、パスワードの長さに関する情報をリークできません。パスワードの長さを推測することを目的としたタイミング攻撃も機能しません。攻撃者がパスワードをブルートフォースにしようとすると、パスワードの検証にかかる時間は、ユーザーの実際のパスワードではなく、パスワードの長さによって異なります。つまり、このような攻撃を実行する攻撃者がユーザーのパスワードの長さを知る方法はありません。
潜在的なDoS攻撃:パスワードを検証するためのCPU消費の増加は、DoS攻撃の原因となる可能性があります。ただし、この攻撃ベクトルは、反復回数が一般的な推奨事項に一致するのに十分な大きさの固定数であっても、すでに存在しています。また、この種のDoS攻撃を防ぐ方法は、クライアントのIP範囲ごとにパスワードの試行をレート制限することです。そのクラスのDoS攻撃に対するこの防御は、CPU消費に応じて許可レートを調整するためにマイナーツイークを適用することを前提として機能します。
ユーザーエクスペリエンス:ログインの速度低下は、ユーザーエクスペリエンスが悪いと考えられます。私はむしろ、ユーザーに長いパスワードを使用し、それを機能と呼ぶ動機を与えると表現したいと思います。ログイン時に、より長いパスワードを使用することでより高速にログインできることをユーザーに知らせることができます。特に、これが広範囲に及ぶ可能性がある場合は、長いパスワードの方が高速であるという期待をユーザーに与える可能性があり、誰にとっても有利です。
これまでの私の考察から、私はこのアイデアの利点のみを見つけました。しかし、私が見逃したかもしれない欠点があるかもしれないことを理解しています。短いパスワードの反復回数を増やしてはいけない理由はありますか?
私が考えているアイデアの曖昧さを回避するために、このアイデアの実装をDjangoフレームワークに記述しました。組み込みのPBKDF2PasswordHasher
そして私の変更はこれらの2行です:
if len(password) < recommended_length:
iterations *= progression_factor**(recommended_length-len(password))
完全な実装は次のようになります。
import base64
import hashlib
from Django.contrib.auth.hashers import PBKDF2PasswordHasher
from Django.utils.crypto import pbkdf2
def progressive_pbkdf2(password, salt, iterations, digest,
recommended_length, progression_factor):
if len(password) < recommended_length:
iterations *= progression_factor**(recommended_length-len(password))
return pbkdf2(password, salt, iterations, digest=digest)
class ProgressivePBKDF2PasswordHasher(PBKDF2PasswordHasher):
algorithm = "progressive_10_2_pbkdf2_sha256"
def encode(self, password, salt, iterations=None):
assert password is not None
assert salt and '$' not in salt
if not iterations:
iterations = self.iterations
hash = progressive_pbkdf2(
password, salt, iterations, digest=self.digest,
recommended_length=10, progression_factor=2)
hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
あなたは技術的な解決策で人間の問題を修正しようとしています。そして、繰り返しになりますが、ユーザーが長いパスワードと短いパスワードで速度の違いを「感じる」という提案があっても、反復の増加がどのように「ユーザーに長いパスワードを使用するように動機づける」かはわかりません。ばかげた値に設定しない限り、バンピングの反復はユーザーには気づかれません。
では、実際にimplement iterations *= progression_factor**(recommended_length-len(password))
を使用する場合、どのような数値について話しているのでしょうか。何万もの?数十万人?何百万?何十億?そして、経験豊富なログインの速度低下は、パフォーマンスの高いサイトをコーディングするための無能とは感じられず、ユーザーの気難しいパスワードが原因であると、ユーザーにどのように教育しますか?
つまり、すべてのアイデアを実装できますが、結局のところ、弱いパスワードは弱いパスワードです。ユーザーが123456
、correct horse battery staple
、Spring2019!
、 10inchcock
、または同様に推測/一般的なパスワードを使用している場合、すべての努力はとにかく無駄に。
私の提案は、より強力なパスワード/パスフレーズを使用するようにユーザーを教育し、基本的なパスワードの衛生を採用するようにユーザーを奨励し、季節、ペットの名前、愛する人、DoBなどの一般的なパターンを使用しないことです。
entropyのようにパスワードを強力にする実際の要素を考慮せず、パスワードの長さのみを考慮しているため、この方法は役に立ちません。漏洩した、または既知のパスワードのデータベース。したがって、correcthorsebatterystaple
または1234567890
は、システムで十分長いと考えられますが、実際には、攻撃者が既知のパスワードの辞書またはデータベースを使用している場合、非常に簡単に解読される可能性があります。
しかし、私が今言ったことを考慮せず、すべてのユーザーがランダムな文字のパスワードだけを使用する理想的な世界に住んでいたとしても、主な問題は次のとおりです。次のシナリオを考えてみます。ここで、最小許容長はシステムが受け入れる最小長であり、理想的なパスワード長は、ユーザーが安全なパスワードを取得するために使用する長さです。パスワードは、記号やすべてを含むランダムな文字列です(94文字)。
Minimum accepted lenght: 6 characters
Passwords to bruteforce: 94^6 = 6.9 x 10^11
Ideal password length: 12 characters
Passwords to bruteforce: 94^12 = 4.76 x 10^23
これは、平均して、理想的なパスワードの解読には、受け入れられる最短のパスワードの約10 ^ 12倍の時間がかかることを意味します。承認された最短のパスワード(6文字)を、解読に理想的なパスワード(12文字)と同じ長さで使用したい場合は、短いパスワードをすべての試行を10 ^ 12倍長くする必要があります。
したがって、理想的なパスワード(12文字)の理想的なハッシュ時間を1秒に設定した場合、受け入れ可能な最小パスワード(6文字)のハッシュ時間を10^12 seconds
に設定する必要があります。これは30以上です。一千年。そして私はユーザーが何千年も待つことをいとわないと思います。実際、ユーザーは数秒以上待つことをいとわないでしょう。したがって、受け入れられる最短のパスワードに対して、各試行に最大3秒かかるとしましょう。次に、理想的なパスワードは3 / 10^12 = 3 picoseconds
でハッシュ化されます。繰り返しますが、これは意味がありません。
ご覧のとおり、問題は、弱いパスワードと十分に強力なパスワードの間で、可能な組み合わせの数に大きな違いがあることですが、その一方で、比較的短い範囲の時間しかありませんあなたまたはあなたのユーザーは許容できると思います。