Чи існують реалізації JavaScript SHA-256, які зазвичай вважаються надійними?


95

Я пишу логін для форуму, і мені потрібно хешувати сторону клієнта пароля в javascript, перш ніж надсилати його на сервер. У мене проблеми з з’ясуванням, якій реалізації SHA-256 я дійсно можу довіряти. Я очікував, що буде якийсь авторитетний сценарій, яким користувались усі, але я знаходжу безліч різних проектів, які мають власну реалізацію.

Я усвідомлюю, що використання криптографії інших людей - це завжди стрибок віри, якщо ви не кваліфіковані переглядати її самостійно, і що не існує універсального визначення поняття "надійний", але це здається чимось досить загальним і важливим, що має бути якийсь консенсусу щодо того, що використовувати. Я просто наївний?

Редагуйте, оскільки цього багато в коментарях: Так, ми знову робимо більш жорсткий хеш на стороні сервера. Хешування на стороні клієнта - це не кінцевий результат, який ми зберігаємо в базі даних. Хешування на стороні клієнта відбувається тому, що це вимагає клієнт-людина. Вони не вказали конкретну причину, чому, напевно, вони просто люблять надмірність.


9
Щоб не відходити від теми, але чому ви хешуєте пароль на стороні клієнта?
Стів

5
@ddyer Навіть близько. "Не катайся самостійно" стосується винайдення власного алгоритму, написання власної реалізації алгоритму, розробки власного протоколу поверх крипто-алгоритмів або майже будь-чого з наведеного вище, використовуючи настільки високий рівень абстракції, як доступно. Якщо ви думаєте, що будете безпечно дотримуватися надійного стрижня і писати лише клейовий код, вам буде погано.
Стівен Тусет,

26
якщо ви використовуєте хешований пароль без протоколу виклику / відповіді, то хешований пароль Є ПАРОЛОМ, і це насправді те саме, що і передача пароля в чистому тексті.
ddyer

26
@ddyer Існує певна цінність захисту відкритого тексту пароля користувача для всіх інших веб-сайтів, на яких він міг би його використовувати, якби не для нашого сайту зокрема. Це просте виправлення, яке, можливо, не допоможе нам, але потенційно може допомогти користувачеві, якщо ми десь зіпсуємось. І як я вже сказав, запит клієнта, я нічого не можу з цим зробити, навіть якби я цього хотів.
jono

4
@Anorov Я більш ніж готовий змінити свою думку :), але в цьому випадку я насправді не розумію, як застосовується ваша думка. Пароль ми хеш два рази: один раз на стороні клієнта за допомогою простого SHA-256 і один раз на стороні сервера з чимось більш вимогливим. Перший для захисту відкритого тексту у випадку MITM або подібного, а другий для захисту від грубих. Навіть якщо у вас є база даних і хеш адміністратора, ви не можете використовувати це безпосередньо для перевірки входу.
jono

Відповіді:


111

Stanford JS Crypto бібліотека містить реалізацію SHA-256. Хоча криптовалюта в JS насправді не настільки перевірена, як інші платформи реалізації, ця, щонайменше, частково розроблена і, певною мірою, спонсорована Ден Боне , який є добре відомим і надійним ім'ям у криптографії. , і означає, що проект має певний контроль з боку того, хто насправді знає, що робить. Проект також підтримується NSF .

Однак варто зазначити ...
... що якщо ви хешуєте пароль на стороні клієнта перед тим, як подавати його, тоді хеш - це пароль , і початковий пароль стає неактуальним. Зловмисникові потрібно лише перехопити хеш, щоб видавати себе за користувача, і якщо цей хеш зберігається незміненим на сервері, тоді сервер зберігає справжній пароль (хеш) у простому тексті .

Отже, ваша безпека зараз гірша, тому що ви вирішили додати власні вдосконалення до того, що раніше була надійною схемою.


31
Однак якщо ви знову хеш на сервері, така практика є цілком законною.
Нік Брант

13
@NickBrunt, якщо у вас є хеш на сервері, ви не зберігаєте переданий пароль, але ви не додали жодної безпеки, окрім передачі оригінального пароля, на відміну від передачі хеша пароля, оскільки в обох випадках те, що ви передаєте, є справжній пароль.
tylerl

54
Правда, але це не гірше, ніж надсилання пароля, який, можливо, використовується деінде в Інтернеті у відкритому тексті.
Нік Брант

15
Я згоден з @NickBrunt. Краще, якщо зловмисник читає випадковий хеш-рядок, який може відповідати лише цій програмі, а не оригінальний пароль, який можна використовувати в декількох місцях.
Aebsubis

12
Мені потрібно використовувати хешування на стороні клієнта, тому що я не хочу, щоб сервер ніколи не бачив відкритий текст користувача. Не для додаткової безпеки служби, яку я надаю, а щодо користувача. Я не лише зберігаю хеш користувача, посолений постійною сіллю (константа для кожного користувача, а не глобально), але і повторний хеш із випадковою сеансовою сіллю при кожному вході, який НАДАЄ трохи додаткового захисту в мережі від нюхання. Якщо сервер стає скомпрометованим, це закінчується, але це справедливо для будь-чого, що не є справді p2p.
Hatagashira,

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у доступному лише на httpsабо localhost- наприклад, для вашого місцевого розвитку, python3 -m http.serverвам потрібно додати цей рядок до вашого /etc/hosts: 0.0.0.0 localhost

Перезавантажте - і ви можете відкрити localhost:8000з робочимcrypto.subtle .


2
Це круто. Дякую. Чи доступний порівнянний API у Node.js?
Con Antonakos

2
Вбудована 'крипто' бібліотека повинна працювати нормально: nodejs.org/dist/latest-v11.x/docs/api/crypto.html
tytho

17

КуватиВпровадження SHA-256 у є швидким та надійним.

Щоб запустити тести на декількох реалізаціях JavaScript SHA-256, перейдіть за посиланням http://brillout.github.io/test-javascript-hash-implementations/ .

Результати на моїй машині підказують, що forge є найшвидшим впровадженням, а також набагато швидшим, ніж криптобібліотека Stanford Javascript Crypto Library (sjcl), згадана у прийнятій відповіді.

Фордж має 256 КБ, але витяг коду, пов'язаного з SHA-256, зменшує розмір до 4,5 КБ, див. 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
Це слід включити до прийнятої відповіді для тих, хто хоче використовувати рішення там. (Чорт візьми, навіть у власних документах немає такого фрагмента)
MagicLegend

Це найкраща відповідь. Я пробував крипто-рішення, але воно не працювало для мене.
Августо Гонсалес

11

Ні, немає можливості використовувати JavaScript браузера для поліпшення захисту паролів. Настійно рекомендую прочитати цю статтю . У вашому випадку найбільшою проблемою є проблема курячих яєць:

У чому полягає "проблема курячого яйця" з доставкою криптографії Javascript?

Якщо ви не довіряєте мережі надавати пароль або, що ще гірше, не довіряєте серверу, що не зберігає таємниці користувачів, ви не можете довірити їм доставку коду безпеки. Той самий зловмисник, який нюхав паролі або читав щоденники перед тим, як ви ввели крипто, просто викрадає крипто-код після вас.

[...]

Чому я не можу використовувати TLS / SSL для доставки криптокоду Javascript?

Ти можеш. Це складніше, ніж здається, але ви безпечно передаєте Javascript crypto до браузера за допомогою SSL. Проблема в тому, що, встановивши захищений канал за допомогою SSL, вам більше не потрібна криптографія Javascript; у вас є "справжня" криптографія.

Що призводить до цього:

Проблема запуску криптокоду в Javascript полягає в тому, що практично будь-яка функція, від якої залежить крипто, може бути безшумно замінена будь-якою частиною вмісту, що використовується для створення сторінки хостингу. Криптозахист може бути скасований на початку процесу (шляхом створення підставних випадкових чисел, або підробки констант та параметрів, що використовуються алгоритмами), або пізніше (шляхом передачі ключового матеріалу назад зловмиснику), або --- у найбільш імовірному сценарії --- повністю обійшовши крипто.

Немає надійного способу для будь-якого фрагмента коду Javascript перевірити середовище його виконання. Крипто-код Javascript не може запитати: "Я справді маю справу з генератором випадкових чисел або з факсимільним файлом, який надає зловмисник?" І це, безумовно, не може стверджувати, що "нікому не дозволяється робити що-небудь із цією криптосекретною службою, за винятком способів, схвалених мною, автором". Це дві властивості, які часто надаються в інших середовищах, що використовують крипто, і в Javascript вони неможливі.

В основному проблема полягає в наступному:

  • Ваші клієнти не довіряють вашим серверам, тому вони хочуть додати додатковий код безпеки.
  • Цей код безпеки постачають ваші сервери (ті, яким вони не довіряють).

Або ж,

  • Ваші клієнти не довіряють SSL, тому вони хочуть, щоб ви використовували додатковий код безпеки.
  • Цей код безпеки доставляється через SSL.

Примітка: Крім того, SHA-256 не підходить для цього, оскільки так легко застосувати несольові неітераційні паролі . Якщо ви вирішили зробити це в будь-якому випадку, подивіться на реалізацію Bcrypt , Scrypt або PBKDF2 .


1
Це неправильно. Захист пароля можна поліпшити, хешуючи на стороні клієнта. Також неправильно, що SHA-256 не підходить, якщо на стороні сервера використовується щось на зразок PBKDF2. По-третє, незважаючи на те, що стаття matasano містить корисну інформацію, перфоманс помилковий, оскільки зараз у нас є програми для браузерів, які принципово змінюють проблему курки та яєць.
user239558

2
Ви маєте рацію, що PBKDF2 слід використовувати на клієнті. Ярості проти крипто-криптографії на стороні клієнта передбачають, що початкова сторінка та наступні запити мають однакові властивості захисту. Очевидно, що це неправда для програм браузера, де початкова сторінка встановлюється окремо і є статичною. Це також не відповідає жодній сторінці із назавжди кеш-семантикою. У цих випадках саме TOFU є точно таким же, як і при встановленні програми на стороні клієнта. Це також може бути справедливим у більш складних установках, де на сервері розділяються статичні та динамічні сторінки.
user239558

3
Законно уникати системних адміністраторів мати доступ до паролів користувачів, тому хешування на стороні клієнта не дозволяє ДБА або іншим ІТ-спеціалістам бачити паролі користувачів та намагатися повторно використовувати їх для доступу до інших служб / систем, оскільки багато користувачів повторюють свої паролі .
Ямада

1
@Xenland Все, що ви робите, - це створити новий пароль, який називається "маркер + пароль". Усі оригінальні проблеми все ще застосовуються. Наприклад, зловмисник може замінити JavaScript кодом, щоб надіслати їм маркер + пароль.
Брендан Лонг

2
@Xenland Проблема з куркою та яйцем не має нічого спільного з надісланими вами запитами. Проблема полягає в тому, що ваш клієнт використовує код JavaScript, який він завантажив через незахищене з’єднання, для виконання заходів безпеки. Єдиний спосіб безпечно надіслати JavaScript у веб-браузер - це обслуговувати його через TLS, і як тільки ви це зробите, вам не потрібно робити нічого іншого, оскільки ваше з’єднання вже захищене. Немає значення, яким є ваш протокол, якщо ви використовуєте код JavaScript, який зловмисник може просто замінити.
Брендан Лонг

10

Я знайшов цю реалізацію дуже простою у використанні. Також має щедру ліцензію у стилі BSD:

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

Мені потрібен був швидкий спосіб отримати шістнадцяткове представлення хешу SHA-256. Це зайняло лише 3 рядки:

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

1

Окрім Стенфордської бібліотеки, яку згадав Тайлер. Я знайшов jsrsasign дуже корисним ( репозиторій Github тут: https://github.com/kjur/jsrsasign ). Я не знаю, наскільки це надійно, але я використовував його API SHA256, Base64, RSA, x509 тощо, і він працює досить добре. Фактично, вона включає також Стенфордську бібліотеку.

Якщо все, що ви хочете зробити, це SHA256, jsrsasign може бути надмірним. Але якщо у вас є інші потреби у відповідній галузі, я вважаю, що це добре підходить.


2
Безпечніше та швидше використовувати developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API
Віталій Зданевич

2
Погодьтеся, але заради справедливості я відповів на це запитання у 2015 році, коли була опублікована специфікація веб-крипто API API від mozilla, січень 2017
Faraway
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.