一般に信頼できると考えられるSHA-256 JavaScript実装はありますか?


95

私はフォーラムのログインを書いており、それをサーバーに送信する前にJavaScriptでクライアント側のパスワードをハッシュする必要があります。私が実際に信頼できるSHA-256実装を理解するのに苦労しています。誰もが使用するある種の権威あるスクリプトが存在することを期待していましたが、すべて独自の実装でさまざまなプロジェクトの負荷を見つけています。

他人の暗号を使用することは、自分でレビューする資格がない限り、常に信念の飛躍であり、「信頼できる」という普遍的な定義はないことを理解していますが、これは一般的で重要なようであり、何らかの種類があるはずです何を使うかについてのコンセンサス。私は単純なのですか?

コメントでたくさん出てくるので編集してください:はい、サーバー側でもう一度より厳しいハッシュを行います。クライアント側のハッシュは、データベースに保存する最終結果ではありません。クライアント側のハッシュは、人間のクライアントが要求するためです。彼らは理由を具体的に述べていませんが、おそらく彼らはやり過ぎを好みます。


9
話題から抜け出すのではなく、なぜクライアント側でパスワードをハッシュしているのですか?
スティーブ

5
@ddyer近くさえない。「独自のものを転がさない」は、独自のアルゴリズムの発明、独自のアルゴリズムの実装の記述、暗号アルゴリズムの上に独自のプロトコルを開発すること、または可能な限り高度な抽象化を使用する上記のほとんどすべてに適用されます。セキュアなコアにこだわって安全で、グルーコードのみを書くと思うなら、悪い時間を過ごすことになります。
Stephen Touset 2013

26
チャレンジ/レスポンスプロトコルなしでハッシュされたパスワードを使用する場合、ハッシュされたパスワードはパスワードであり、クリアテキストでパスワードを送信することと同じです。
ddyer 2013

26
@ddyer特に私たちのサイトではなくても、ユーザーが使用する可能性のある他のすべてのサイトのユーザーのプレーンテキストパスワードを保護することには、いくつかの価値があります。これは簡単な修正であり、私たちには役に立たないかもしれませんが、どこかで失敗した場合にユーザーを助ける可能性があります。そして、私が言ったように、クライアントの要求、私が望んでもそれについて私は何もできません。
jono 2013

4
@Anorov私は私の心を変えることを受け入れるだけではありません:)しかし、この場合、私はあなたのポイントがどのように適用されるのか本当に理解していません。パスワードを2回ハッシュします。1回は単純なSHA-256を使用してクライアント側で、もう1回は要求の厳しいものを使用してサーバー側でハッシュします。1つ目はMITMまたは類似の場合に平文を保護し、2つ目はブルートプロテクション用です。データベースと管理ハッシュを手に入れても、それを直接使用してログインを検証することはできません。
jono 2013

回答:


111

スタンフォードJS暗号ライブラリは、 SHA-256の実装が含まれています。JSでの暗号化は他の実装プラットフォームほど実際には十分に吟味されていませんが、これは少なくとも部分的には暗号化で確立され信頼されている名前であるDan Bonehによって開発され、ある程度後援されています。 、そして彼のプロジェクトを実際に知っている誰かによるプロジェクトの監督があることを意味します。プロジェクトはNSFによってもサポートされています。

ただし、指摘する価値があります...
...クライアント側でパスワードをハッシュ化してから送信すると、そのハッシュがパスワードになり、元のパスワードは無関係になります。攻撃者はユーザーを偽装するためにハッシュを傍受するだけでよく、そのハッシュが変更されずにサーバーに保存されている場合、サーバーは本当のパスワード(ハッシュ)を平文で保存しています

したがって、以前は信頼されていたスキームに独自の改善加えることを決定しため、セキュリティが悪化しています。


31
ただし、サーバーで再度ハッシュする場合、この方法は完全に正当です。
Nick Brunt 2013年

13
@NickBruntサーバーでハッシュした場合、送信されたパスワードは保存されませんが、どちらの場合も送信しているものが実際のパスワード。
tylerl 2013年

54
本当ですが、インターネットの他の場所で使用されている可能性のあるパスワードをプレーンテキストで送信するよりも悪くはありません。
Nick Brunt 2013年

15
@NickBruntに同意します。攻撃者が、いくつかの場所で使用される可能性のある元のパスワードではなく、この特定のアプリにのみ適合する可能性のあるランダムなハッシュ文字列を読み取る場合は、より良いです。
Aebsubis 2014年

12
サーバーにユーザーのプレーンテキストのパスワードが表示されないようにするため、クライアント側のハッシュを使用する必要があります。私が提供するサービスにセキュリティを追加するためではなく、ユーザー向けです。ユーザーのハッシュを一定のソルト(グローバルではなく、ユーザーごとに一定)で保存するだけでなく、ログインごとにランダムなセッションソルトでハッシュを再ハッシュします。これにより、ネットワーク上でスニッフィングに対するセキュリティが少し強化されます。サーバーが危険にさらされた場合、それはゲームオーバーですが、とにかく真にp2pでない場合はそれが当てはまります。
幡ヶ頭2014年

49

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest私は内部のjsモジュールを使用して、このスニペットを見つけました:

async function sha256(message) {
    // encode as UTF-8
    const msgBuffer = new TextEncoder('utf-8').encode(message);                    

    // hash the message
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);

    // convert ArrayBuffer to Array
    const hashArray = Array.from(new Uint8Array(hashBuffer));

    // convert bytes to hex string                  
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex;
}

またはcrypto.subtleでのみ使用できることに注意してください-たとえば、ローカル開発の場合は、この行を次の行に追加する必要があります。 httpslocalhostpython3 -m http.server/etc/hosts0.0.0.0 localhost

再起動するlocalhost:8000と、作業を開始できますcrypto.subtle


2
これは素晴らしいです。ありがとうございました。Node.jsで同等のAPIを利用できますか?
Con Antonakos、2018

2
組み込みの「crypto」ライブラリは問題なく機能するはずです:nodejs.org/dist/latest-v11.x/docs/api/crypto.html
tytho

17

ForgeのSHA-256実装は高速で信頼性があります。

複数のSHA-256 JavaScript実装でテストを実行するには、http://brillout.github.io/test-javascript-hash-implementations/にアクセスしてください。

私のマシンの結果は、forgeが最も速い実装であり、受け入れられた回答で述べられているStanford Javascript Crypto Library(sjcl)よりもかなり高速であることを示唆しています。

Forgeのサイズは256 KBですが、SHA-256関連のコードを抽出するとサイズが4.5 KBに減少します。https://github.com/brillout/forge-sha256を参照してください


でインストールnpm install node-forgeできましたが、ライブラリを使用して文字列からハッシュを作成するにはどうすればよいfooですか?
ユーザー

15

興味がある人のために、これはSHA-256ハッシュを作成するためのコードですsjcl

import sjcl from 'sjcl'

const myString = 'Hello'
const myBitArray = sjcl.hash.sha256.hash(myString)
const myHash = sjcl.codec.hex.fromBits(myBitArray)

4
これは、そこでソリューションを使用したい人のための受け入れられた回答に組み込まれる必要があります。(
いや

これが最良の答えです。暗号化ソリューションを試してみましたが、うまくいきませんでした。
アウグストゴンザレス

11

いいえ、ブラウザのJavaScriptを使用してパスワードのセキュリティを向上させる方法はありません。この記事を読むことを強くお勧めします。あなたの場合、最大の問題は鶏卵問題です:

Javascript暗号化の配信に伴う「鶏卵問題」とは何ですか?

ネットワークがパスワードを配信することを信頼しない場合、またはさらに悪いことに、サーバーがユーザーの秘密を保持しないことを信頼しない場合、セキュリティコードを配信することは信頼できません。暗号を導入する前にパスワードを盗聴したり、日記を読んだりした同じ攻撃者は、暗号を導入した後、単に暗号コードを乗っ取っているだけです。

[...]

TLS / SSLを使用してJavascript暗号コードを配信できないのはなぜですか?

あなたはできる。思ったより難しいですが、SSLを使用してJavascript暗号をブラウザに安全に送信できます。問題は、SSLで安全なチャネルを確立すると、Javascript暗号化が不要になることです。「本当の」暗号法があります。

これにつながる:

JavaScriptで暗号コードを実行する際の問題は、暗号が依存する実質的にすべての機能が、ホスティングページの構築に使用されるコンテンツの一部によって暗黙的にオーバーライドされる可能性があることです。暗号セキュリティは、プロセスの早い段階で(偽の乱数を生成するか、アルゴリズムで使用される定数とパラメーターを改ざんすることにより)、または後で(キーマテリアルを攻撃者にスピリットさせることにより)、または--- 最も可能性の高いシナリオで元に戻すことができます---暗号を完全にバイパスする。

Javascriptコードがその実行環境を検証するための信頼できる方法はありません。Javascriptの暗号コードは、「乱数ジェネレーターを実際に扱っているのか、それとも攻撃者から提供されたものの一部をファクシミリで扱っているのか」と尋ねることはできません。そして、それは「著者、私が承認する方法を除いて、誰もこの暗号の秘密で何もすることを許可されていない」と断言することはできません。これらは、暗号を使用する他の環境でしばしば提供される2つのプロパティであり、JavaScriptでは不可能です。

基本的に問題はこれです:

  • クライアントはサーバーを信頼していないため、セキュリティコードを追加したいと考えています。
  • そのセキュリティコードは、サーバー(サーバーが信頼しないサーバー)によって配信されます。

または、代わりに

  • クライアントはSSLを信頼していないため、追加のセキュリティコードを使用してほしいと考えています。
  • そのセキュリティコードはSSL経由で配信されます。

注:また、SHA-256は、ソルト処理されていない非反復パスワードブルートフォースで攻撃するのが非常に簡単であるため、これには適していません。とにかくこれを行うことにした場合は、bcryptscryptまたはPBKDF2の実装を探してください


1
これは正しくありません。パスワードのセキュリティは、クライアント側でハッシュすることによって改善できます。サーバー側でPBKDF2のようなものが使用されている限り、SHA-256が適さないことも誤りです。第3に、matasanoの記事には有益な洞察が含まれていますが、鶏と卵の問題を根本的に変えるブラウザアプリがあるため、重要な点は間違っています。
user239558 2013年

2
クライアントでPBKDF2を使用するのは正しいことです。クライアント側のjavascript暗号に対する怒りは、最初のページと後続の要求が同じセキュリティプロパティを持っていると想定しています。これは、初期ページが個別にインストールされ、静的であるブラウザーアプリには明らかに当てはまりません。また、永久キャッシュのセマンティクスを持つページには当てはまりません。これらの場合、クライアント側のプログラムをインストールするときとまったく同じです。これは、静的ページと動的ページの提供がサーバー上で分離されている、より複雑な設定でも当てはまります。
user239558 2013年

3
システム管理者がユーザーパスワードにアクセスできないようにすることは正当です。そのため、クライアント側でのハッシュにより、DBAや他のIT専門家がユーザーのパスワードを確認し、それを再利用して他のサービスやシステムにアクセスしようとするのを防ぐことができます。 。
山田

1
@Xenlandあなたがしているのは、「トークン+パスワード」である新しいパスワードを作成することだけです。元の問題はすべてまだ当てはまります。たとえば、攻撃者はJavaScriptをコードに置き換えて、トークンとパスワードを送信することができます。
ブレンダンロング、

2
@Xenland鶏と卵の問題は、送信するリクエストとは何の関係もありません。問題は、クライアントが安全でない接続介してダウンロードした JavaScriptコード使用してセキュリティ作業を行っていることです。JavaScriptを安全にWebブラウザーに送信する唯一の方法は、TLSを介してJavaScriptを提供することです。これを行うと、接続は既に安全であるため、他に何もする必要はありません。攻撃者が置き換えることができるJavaScriptコードを使用している場合、プロトコルが何であるかは関係ありません。
ブレンダンロング

10

この実装は非常に使いやすいと思いました。また、寛大なBSDスタイルのライセンスがあります。

jsSHA:https : //github.com/Caligatio/jsSHA

SHA-256ハッシュの16進文字列表現を取得する簡単な方法が必要でした。たった3行で済みました。

var sha256 = new jsSHA('SHA-256', 'TEXT');
sha256.update(some_string_variable_to_hash);
var hash = sha256.getHash("HEX");

1

タイラーが言及したスタンフォードlibのほかに。私はjsrsasignが非常に便利であることを発見しました(Github repo here:https : //github.com/kjur/jsrsasign)。どれほど正確に信頼できるかはわかりませんが、SHA256、Base64、RSA、x509などのAPIを使用したので、かなりうまくいきます。実際には、スタンフォードlibも含まれています。

もしあなたがやりたいことがSHA256なら、jsrsasignはやり過ぎかもしれません。しかし、あなたが関連分野で他のニーズを持っているなら、それはぴったりだと思います。



2
同意しますが、公平を期すために、私はこの質問に2015年に回答しましたが、mozillaのWeb暗号API仕様は2017
遠く
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.