node.bcrypt.js는 솔트가없는 해시 된 암호와 일반 텍스트 암호를 어떻게 비교합니까?


95

에서 GitHub의 :

암호를 해시하려면 :

var bcrypt = require('bcrypt');
bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash("B4c0/\/", salt, function(err, hash) {
        // Store hash in your password DB.
    });
});

비밀번호를 확인하려면 :

// Load hash from your password DB.
bcrypt.compare("B4c0/\/", hash, function(err, res) {
    // res == true
});
bcrypt.compare("not_bacon", hash, function(err, res) {
    // res = false
});

위에서 어떻게 비교에 소금 값이 없을 수 있습니까? 내가 여기서 무엇을 놓치고 있습니까?

답변:


98

솔트는 해시에 통합됩니다 (일반 텍스트). 비교 기능은 단순히 해시에서 솔트를 가져온 다음이를 사용하여 암호를 해시하고 비교를 수행합니다.


1
아직도 이해가 안 돼요. 비교하는 동안 소금을 제공하지 않으면 해시의 어느 부분이 소금인지 어떻게 알 수 있습니까?
MondayPaper 2014 년

7
bcrypt는 표준이며 항상 동일한 형식의 해시와 솔트를 연결합니다. 암호화 할 때 솔트를 제공하면 해시에 통합됩니다. bcrypt는 원래 bcrypt를 사용하여 암호화 된 데이터 만 해독 할 수 있습니다. 그렇지 않으면 맞습니다. 어느 부분이 해시이고 어느 부분이 솔트인지 알 수있는 방법이 없습니다.
Bill

6
좋아요, 우리는 그것을 얻습니다 : 소금은 해시와 함께 저장됩니다. bcrypt는 오픈 소스이므로 모든 사람이 정확히 저장하는 방법을 알고 있습니다. 따라서 그것을 추출하는 방법 또는 일반 텍스트 암호에서 해시를 생성하는 방법을 알고 있습니다. 이것이 기본적으로 솔트의 기본 개념 인 해시를 찾기 위해 레인보우 테이블을 스캔하지 못하도록 암호를 보호하는 데 어떻게 도움이됩니까?
Vitaliy Lebedev 2011

13
공격자가 특정 해시에 대한 솔트를 알고 있는지 여부는 중요하지 않으며 비밀이 아닙니다. 각 암호에 다른 솔트를 사용한다는 것은 공격자가 공통 값을 사용하여 해시를 미리 계산할 수 없음을 의미합니다. 각각에 다른 솔트를 사용하면 모든 암호에 대해 테이블을 다시 계산하여 쓸모 없게 만듭니다.
Bill

3
공격자가 데이터베이스에서 특정 사용자에 대한 솔트를 다음 column_password = hash, column_salt = salt과 같이 알고 있는지 여부가 중요합니까 column_password = hash_salt? 공격자는 여전히 동일한 정보를 가지고 있습니다. 요점은 모든 암호를 무작위로 더 크게 만들어 누군가가 미리 계산할 가능성이 없게 만드는 것입니다.
Muhammad Umer

27

나도 원래 포스터와 같은 질문을했고 메커니즘을 이해하기 위해 주위를 둘러 보며 여러 가지 시도를했습니다. 다른 사람들이 이미 지적했듯이 솔트는 최종 해시에 연결됩니다. 따라서 이것은 몇 가지를 의미합니다.

  1. 알고리즘은 소금의 길이를 알아야합니다.
  2. 최종 문자열에서 소금의 위치도 알아야합니다. 예를 들어 왼쪽 또는 오른쪽에서 특정 숫자만큼 오프셋 된 경우.

이 두 가지가 일반적으로 하드 구현에 코딩 등의 bcrypt 구현 소스 bcryptjs는 16 소금 길이를 정의

/**
* @type {number}
* @const
* @private
*/

var BCRYPT_SALT_LEN = 16;

따라서 아이디어의 기본 개념을 설명하기 위해 수동으로 수행하려는 경우 아래와 유사하게 보일 것입니다. 나는 당신이 그것을 할 수있는 라이브러리가있을 때 이와 같은 것을 직접 구현하는 것을 권장하지 않습니다.

var salt_length = 16;
var salt_offset = 0;

var genSalt = function(callback)
{
    var alphaNum = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
    var salt = '';
    for (var i = 0; i < salt_length; i++) {
        var j = Math.floor(Math.random() * alphaNum.length);
        salt += alphaNum[j];
    }
    callback(salt);
}

// cryptographic hash function of your choice e.g. shar2
// preferably included from an External Library (dont reinvent the wheel)
var shar2 = function(str) {
    // shar2 logic here 
    // return hashed string;
}

var hash = function(passwordText, callback)
{
    var passwordHash = null;
    genSalt(function(salt){
        passwordHash = salt + shar2(passwordText + salt);
    });

    callback(null, passwordHash);
}

var compare = function(passwordText, passwordHash, callback)
{
    var salt = passwordHash.substr(salt_offset, salt_length);
    validatedHash = salt + shar2(passwordText + salt);

    callback(passwordHash === validatedHash);   
}

// sample usage
var encryptPassword = function(user)
{
    // user is an object with fields like username, pass, email
    hash(user.pass, function(err, passwordHash){
        // use the hashed password here
        user.pass = passwordHash;
    });

    return user;
}

var checkPassword = function(passwordText, user)
{
    // user has been returned from database with a hashed password
    compare(passwordText, user.pass, function(result){
        // result will be true if the two are equal
        if (result){
            // succeeded
            console.log('Correct Password');
        }
        else {
            // failed
            console.log('Incorrect Password');
        }
    });
}

1

Bcrypt는 해시 된 암호에 해시 할 때 생성 한 솔트 문자열이 포함되어 있기 때문에 솔트 문자열없이 해시 된 암호와 일반 텍스트 암호를 비교합니다.

예 :

이 일반 암호 사용 :

546456546456546456456546111

Bcrypt를 사용하는 위의 일반 텍스트의 해시 된 암호 :

$ 2b $ 10 $ uuIKmW3Pvme9tH8qOn / H7uZqlv9ENS7zlIbkMvCSDIv7aup3WNH9W

따라서 위의 해시 된 암호에는 $로 구분 된 세 개의 필드가 있습니다. 기호로 .

i) 첫 부분 $ 2b $ 는 사용 된 bcrypt 알고리즘 버전을 식별합니다.

ii) 두 번째 부분 $ 10 $ 10이 비용 요소입니다 (솔트 문자열을 만드는 동안 소금 라운드 만 발생합니다. 15 라운드를 수행하면 값은 $ 15 $가됩니다.

iii) 세 번째 부분은 처음 22 자입니다 (솔트 문자열 일뿐입니다).

uuIKmW3Pvme9tH8qOn / H7u

나머지 문자열은 해시 된 암호입니다. 따라서 기본적으로 saltedHash = salt string + hashedPassword는 레인보우 테이블 공격으로부터 보호합니다.


0

저도 같은 질문을했기 때문에 당신이 무슨 생각을하는지 정확히 알고 있습니다.

암호화 알고리즘에 사용되는 "Secret Key" 와 암호화 프로세스를 늦추고 해커가 무차별 대입을 어렵게 만드는 데 사용되는 "Salt" 사이에 오해 가 있습니다.

당신이 사용하는 경우 일반 암호 해시를 생성하고 소금을이 해시는 비밀 키 암호 자체로 사용 ! 따라서 다음에 일반 암호와 비교하려고 할 때이 일반 암호는 해시를 생성하는 데 사용한 것과 동일해야합니다! 따라서 등록 및 로그인 단계에서 항상 사용자가 제공하므로 다른 곳에 저장할 필요가 없습니다!


0

소금은 해시에 통합됩니다. 비교 기능은 단순히 해시에서 솔트를 가져온 다음이를 사용하여 암호를 해시하고 비교를 수행합니다.

사용자가 시스템에 로그인 할 때 입력 한 암호가 올바른지 확인해야합니다. 데이터베이스에서 암호를 해독하고 (암호화 된 경우) 사용자가 입력 한 암호와 비교하는 다른 시스템과 달리 bcrypt로 수행하는 작업 (단방향 해싱을 구현하는 경우)은 암호를 암호화하는 것입니다. 사용자. 이를 위해 암호를 bcrypt에 전달하여 해시를 계산할뿐만 아니라 사용자 (해시)와 관련된 데이터베이스에 저장된 암호도 계산합니다. 이는 앞에서 언급했듯이 bcrypt 알고리즘이 임의 세그먼트 (salt)를 사용하여 pasword와 관련된 해시를 생성하기 때문입니다. 이것은 암호와 함께 저장되었으며 사용자가 입력 한 암호의 해시를 다시 계산하고 마지막으로 등록 할 때 입력 한 것과 비교하여 일치하는지 확인하는 데 필요합니다.


0

고정 된 길이의 문자열입니다.

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);

console.log("");
var salt = bcrypt.genSaltSync(10);
console.log(salt);
hash = bcrypt.hashSync("foobar", salt);
console.log(hash);
$2a$10$onmcKV.USxnoQAsQwBFB3e
$2a$10$onmcKV.USxnoQAsQwBFB3eytL3UZvZ5v/SudaWyaB9Vuq9buUqGO2

$2a$10$mwQfdyVS9dsO4SuxoR5Ime
$2a$10$mwQfdyVS9dsO4SuxoR5ImeG7atz7RXGRXb.c0VHp5zSn1N2VOA.Vq

$2a$10$uVUuJr6LryjchhKEg6PH7u
$2a$10$uVUuJr6LryjchhKEg6PH7unTw8aJGK0i3266c5kqDBLJkf80RHEpq

$2a$10$Y.upG5/54zvJyZacRxP17O
$2a$10$Y.upG5/54zvJyZacRxP17OH60BC0hQRMNfQjJxSWE77fyBrbzalmS
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.