Jak mogę uzyskać skrót sha1 ciągu w node.js?

108

Próbuję utworzyć serwer websocket napisany w node.js.

Aby serwer działał, potrzebuję skrótu SHA1 ciągu.

To, co muszę zrobić, zostało wyjaśnione w sekcji 5.2.2 na stronie 35 dokumentacji .

UWAGA: Na przykład, jeśli wartość "Sec-WebSocket-Key" nagłówka w uzgadnianiu klienta "dGhlIHNhbXBsZSBub25jZQ=="byłaby, serwer dołączyłby łańcuch, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"aby utworzyć ciąg "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". Następnie serwer pobierze skrót SHA-1 tego ciągu, dając wartość 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. Ta wartość jest następnie zakodowana w formacie base64, aby uzyskać wartość "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", która zostanie zwrócona w "Sec-WebSocket-Accept"nagłówku.

Eric
źródło
9
Chciałbym bardzo polecić pomocą doskonałą socket.io bibliotekę zamiast toczenia własne. Nie tylko zostało to szeroko przetestowane i poprawione, ale obsługuje większość przeglądarek (nawet te bez interfejsu API WebSocket) różnymi metodami.
Alex Turpin
1
Dobre odniesienie dla przyszłych odwiedzających: stackoverflow.com/questions/9407892/…
Damodaran

Odpowiedzi:

32

Obowiązkowe: SHA1 jest zepsute , możesz obliczyć kolizje SHA1 za 45 000 USD . Powinieneś użyć sha256:

var getSHA256ofJSON = function(input){
    return crypto.createHash('sha256').update(JSON.stringify(input)).digest('hex')
}

Aby odpowiedzieć na twoje pytanie i utworzyć skrót SHA1:

const INSECURE_ALGORITHM = 'sha1'
var getInsecureSHA1ofJSON = function(input){
    return crypto.createHash(INSECURE_ALGORITHM).update(JSON.stringify(input)).digest('hex')
}

Następnie:

getSHA256ofJSON('whatever')

lub

getSHA256ofJSON(['whatever'])

lub

getSHA256ofJSON({'this':'too'})

Oficjalna dokumentacja węzła crypto.createHash()

mikemaccana
źródło
7
Dobry pomysł. Należy jednak pamiętać, że wszystkie obiekty (z wyjątkiem tablic i wartości null) będą miały tę samą wartość sha1sum, ponieważ domyślnie Object.toString()zwracane [object Object]. A więc sha1sum({})=== sha1sum({"foo":"bar"})=== sha1sum({"a":1}), itd.
maerics
sha1 (JSON.stringify ("jakiś ciąg")) => sha1 ("\" jakiś napis \ ""), co jest absolutnie nieoczekiwane i nie jest przeznaczone na wiele platform. Czasami lepsze jest wrogiem dobra.
Pierre
3
Oczekuje się, że sha1 danego ciągu będzie taki sam na każdej platformie. Twoja implementacja za pomocą JSON.stringify zmienia oryginalny ciąg znaków, a sha1sum ("abcd") daje f805c8fb0d5c466362ce9f0dc798bd5b3b32d512, gdzie każdy mógłby się spodziewać 81fe8bfe87576c3ecb22426f8e57847382917acf
Pierre
2
@Pierre To doskonała uwaga. Myślę, że nazwanie funkcji sha1sumjest niedokładne, biorąc pod uwagę to, co powiedziałeś - to najwyraźniej robi więcej niż normalny sha1. W odpowiedzi zmieniłem nazwę funkcji.
mikemaccana
Na dzień dzisiejszy nie jest znana żadna kolizja standardowego 80-
rundowego
8

Proszę przeczytać i mocno rozważyć moje rady w komentarzach do Twojego postu. Biorąc to pod uwagę, jeśli nadal masz dobry powód, aby to zrobić, sprawdź tę listę modułów kryptograficznych dla Node . Posiada moduły do ​​obsługi zarówno sha1, jak i base64.

Alex Turpin
źródło
7

Wskazówki dotyczące zapobiegania problemom (zły hash):

Doświadczyłem, że NodeJS haszuje reprezentację łańcucha znaków w formacie UTF-8. Inne języki (takie jak Python, PHP lub PERL ...) haszują ciąg bajtów.

Możemy dodać argument binarny, aby użyć ciągu bajtów.

const crypto = require("crypto");

function sha1(data) {
    return crypto.createHash("sha1").update(data, "binary").digest("hex");
}

sha1("Your text ;)");

Możesz spróbować z: „\ xac”, „\ xd1”, „\ xb9”, „\ xe2”, „\ xbb”, „\ x93” itd ...

Inne języki (Python, PHP, ...):

sha1("\xac") //39527c59247a39d18ad48b9947ea738396a3bc47

Nodejs:

sha1 = crypto.createHash("sha1").update("\xac", "binary").digest("hex") //39527c59247a39d18ad48b9947ea738396a3bc47
//without:
sha1 = crypto.createHash("sha1").update("\xac").digest("hex") //f50eb35d94f1d75480496e54f4b4a472a9148752
A-312
źródło
1
'binary'- Alias ​​dla 'latin1' nodejs.org/api/…
Harush,
1
^^ Niezwykle ważna uwaga autorstwa @JossefHarush! Jeśli nie musisz specjalnie kodować tekstu jako latin1 przed haszowaniem (np. Dokładnie dla zgodności z PHP) i jest jakakolwiek szansa, że ​​twój tekst zawiera symbole Unicode spoza zakresu latin1 (np. Emoji!), Nie używaj binary! Użycie binarylub latin1w kodowaniu spowoduje utratę informacji i zwiększy prawdopodobieństwo kolizji! Wypróbuj powyższy fragment z tymi dwoma, na przykład: i
cbr
Wszystkie skróty są wykonywane na danych binarnych. Problem polega na tym, że inne wspomniane języki nie używają UTF-8, a nie na odwrót. Stanie się to bardzo widoczne, gdy spróbujesz zaszyfrować coś poza Latin1. W szczególności w przypadku PHP kodowanie jest całkowicie określane przez źródło, takie jak sam plik tekstowy dla tekstu zakodowanego na stałe. Perl może potrzebować ciężkiego podnoszenia, aby używać UTF-8.
Ryan Hanekamp
3

Możesz użyć:

  const sha1 = require('sha1');
  const crypt = sha1('Text');
  console.log(crypt);

Do zainstalowania:

  sudo npm install -g sha1
  npm install sha1 --save
user944550
źródło
Witaj użytkowniku944550, witaj. Rozważ dodanie dodatkowych informacji.
Tiago Martins Peres 李大仁