翻訳者から:以下に翻訳されたNajaf Aliの記事の約束は少し宣伝されていますが(「暗号化は私たちの専門家に任せてください」)、説明されている例は非常に興味深く、注目に値します。
さらに、共通の真実を繰り返すことは決して不要ではありません。暗号保護を発明しないでください。 そして、この記事はその理由を完全に説明しています。
コンピテンシーには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 }
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
challenge_mac = params.delete(:mac)
message = params.each.map { |key, value| "#{key}:#{value}" }.join('&')
calculated_mac = OpenSSL::Digest::MD5.hexdigest(secret + message)
if challenge_mac == calculated_mac
else
end
, MD5, API. , ?
?, "
" (
Length extension attack).
:
md5('foo')
, MD5 md5('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
challenge_hmac = params.delete(:hmac)
message = params.each.map { |key, value| "#{key}:#{value}" }.join('&')
calculated_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), secret, message)
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 — . . , .