さらに、共通の真実を繰り返すことは決して不要ではありません。暗号保護を発明しないでください。 そして、この記事はその理由を完全に説明しています。
コンピテンシーには4つの段階があります。
- 無意識の無能 -自分が無能であることがわからず、無能であることがどれほど大きいか。
- 無意識の無能 -自分の無能と、状況を改善するために必要なステップを知っているとき。
- 意識的な能力 -あなたが上手で、それについて知っているとき。 (これはすごい!)
- 無意識の能力 -あなたがそれについてもはや知らないほど上手なとき。
私たちは皆、それが好きかどうかにかかわらず、最初の段階から始めます。 あらゆる分野でステージ1からステージ2に移行するための鍵は、多くの間違いを犯し、応答を取得することです。 応答があった場合、あなたは正しいことをしたこと、何が間違っていたのか、次に何を改善すべきかを理解し始めます。
暗号化は危険です。何か間違ったことをしても反応が得られないからです。 平均的な開発者にとって、ベース64でエンコードされたランダムバイトの1つのブロックは、他のブロックと同じくらい優れています。
不注意でプログラムを学習することができます。 コードがコンパイルされない場合、必要なことを実行しない場合、または簡単に検出可能なバグが含まれている場合は、すぐに応答します。 すべてを修正すれば、次回は良くなります。
暗号は意図せずに学習することはできません。 脆弱性に関する資料を読んで使用しようとしない場合、自社開発の暗号化ベースの保護メカニズムは実際の攻撃に対してほとんどチャンスがありません。
暗号化ベースのセキュリティメカニズムを解読する方法を知っているセキュリティの専門家にお金を払わないと、コードが安全でないことがわかりません。 あなたの防御を迂回する攻撃者もあなたを助けません(理想的には、彼らはあなたがそれについて決して知らないようにそれを迂回することができるでしょう)。
以下は、暗号化の誤用のいくつかの例です。 考えてみてください。もしこの投稿を読んでいなかったら、実際にこれらのエラーを見つけることができますか?
写真共有サイトの認証API
MD5 +シークレットを使用したメッセージ認証
1つの写真共有サイトは、次のスキームを使用して、何らかの方法でAPIへのリクエストを認証しました。
- ユーザーには次の詳細があります。
- 自分自身を識別するパブリックユーザーID (プレーンテキストで転送しても安全です)
- メッセージに署名するサーバーと共有されるシークレット(シークレットを保持する必要があります)
- API HTTP ( HTTPS — ). POST/GET (,
{ action: create, name: 'my-new-photo' }
). - , user id . — MD5 , -.
, , , .
:
#
require 'openssl'
##
user_id = '42'
secret = 'OKniSLvKZFkOhlo16RoTDg0D2v1QSBQvGll1hHflMeO77nWesPW+YiwUBy5a'
## ,
params = { foo: 'bar', bar: 'baz', user_id: user_id }
## MAC
message = params.each.map { |key, value| "#{key}:#{value}" }.join('&')
params[:mac] = OpenSSL::Digest::MD5.hexdigest(secret + message)
## - ...
HTTP.post 'api.example.com/v3', params
#
##
user = User.find(params[:user_id])
secret = user.secret
## MAC
challenge_mac = params.delete(:mac)
## MAC , ,
message = params.each.map { |key, value| "#{key}:#{value}" }.join('&')
calculated_mac = OpenSSL::Digest::MD5.hexdigest(secret + message)
## MAC
if challenge_mac == calculated_mac
# - ,
else
# ,
end
, MD5, API. , ? ?
, " " (Length extension attack).
:
-
md5('foo')
, MD5md5('foobar')
, 'foo'. -
md5('secretfoo:bar')
,md5('secretfoo:bar&bar:baz')
, 'secret'. - , , . .
, , . Flickr, Vimeo Remember the Milk (pdf).
, . , . .
? , , …
HMAC
Hash-based Message Authentication Code (HMAC) .
! HMAC . , --.
:
require 'openssl'
##
user = User.find(params[:user_id])
secret = user.secret
## HMAC
challenge_hmac = params.delete(:hmac)
## HMAC
## ,
message = params.each.map { |key, value| "#{key}:#{value}" }.join('&')
calculated_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), secret, message)
## HMAC
if challenge_hmac == calculated_hmac
# - ,
else
# ,
end
, ? ?
, (Timing attack), HMAC .
:
- HMAC, . ASCII — 'aaaa...', 'bbbb...' ..
- . - , , , , HMAC.
- :
- -, . - , , .
- , . , — 'x', HMAC 'xaaa...', 'xbbb...' ..
- , HMAC .
, HMAC , API, .
-, , , . , . , . .
…
HMAC
, HMAC . .. , , .
, XOR 0. , — XOR A B, true, 0, false .
Ruby - :
require 'openssl'
## ,
def secure_equals?(a, b)
return false if a.length != b.length
a.bytes.zip(b.bytes).inject(0) { |sum, (a, b)| sum |= a ^ b } == 0
end
##
user = User.find(params[:user_id])
secret = user.secret
## HMAC
challenge_hmac = params.delete(:hmac)
## HMAC
## ,
message = params.each.map { |key, value| "#{key}:#{value}" }.join('&')
calculated_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), secret, message)
## HMAC
if secure_equals?(challenge_hmac, calculated_hmac)
# - ,
else
# ,
end
, ? ?
. . , .
. . . .
P.S. HMAC activesupport,
ActiveSupport::MessageVerifier
. . .
P.P.S. ? Matasano Crypto Challenges — , . , , .
: Najaf Ali — . . , .