如何为RabbitMQ Management HTTP API生成password_hash

Din*_*nei 11 c# rabbitmq rabbitmqadmin

心爱的RabbitMQ管理插件有一个HTTP API,可以通过普通的HTTP请求来管理RabbitMQ.

我们需要以编程方式创建用户,并且HTTP API是您选择的方式.文档很少,但API非常简单直观.

关注安全性,我们不希望以纯文本形式传递用户密码,而API提供了一个字段来代替发送密码哈希.从那里引用:

[GET | PUT | DELETE]/api/users/name

个人用户.要使用户,你需要一个看起来像这样的身体:

{"password":"secret","tags":"administrator"}
Run Code Online (Sandbox Code Playgroud)

要么:

{"password_hash":"2lmoth8l4H0DViLaK9Fxi6l9ds8=", "tags":"administrator"}
Run Code Online (Sandbox Code Playgroud)

标签键是必需的.无论是passwordpassword_hash必须设置.

到目前为止,这么好,问题是:如何正确生成password_hash

密码散列算法被配置在RabbitMQ的配置文件,我们的配置为默认SHA256.

我正在使用C#,以下代码生成哈希:

var cr = new SHA256Managed();
var simplestPassword = "1";
var bytes = cr.ComputeHash(Encoding.UTF8.GetBytes(simplestPassword));
var sb = new StringBuilder();
foreach (var b in bytes) sb.Append(b.ToString("x2"));
var hash = sb.ToString();
Run Code Online (Sandbox Code Playgroud)

这不起作用.在一些用于SHA256加密的在线工具中进行测试,代码产生了预期的输出.但是,如果我们转到管理页面并手动将用户密码设置为"1",那么它就像魅力一样.

这个答案让我导出配置并看看RabbitMQ正在生成的哈希值,我意识到了一些事情:

  • 哈希示例"1":"y4xPTRVfzXg68sz9ALqeQzARam3CwnGo53xS752cDV5 + Utzh"
  • 所有用户的哈希都有固定长度
  • 哈希每次都会改变(即使密码相同).我知道PB2K也会对密码执行此操作,但不知道此加密属性的名称.
  • 如果我通过password_hashRabbitMQ存储它没有更改

我也接受其他编程语言的建议,而不仅仅是C#.

Wal*_*ldo 14

And for the fun the bash version !

#!/bin/bash

function encode_password()
{
    SALT=$(od -A n -t x -N 4 /dev/urandom)
    PASS=$SALT$(echo -n $1 | xxd -ps | tr -d '\n' | tr -d ' ')
    PASS=$(echo -n $PASS | xxd -r -p | sha256sum | head -c 128)
    PASS=$(echo -n $SALT$PASS | xxd -r -p | base64 | tr -d '\n')
    echo $PASS
}

encode_password "some-password"
Run Code Online (Sandbox Code Playgroud)


Der*_*ley 11

来自:http://rabbitmq.1065348.n5.nabble.com/Password-Hashing-td276.html

但是,如果您想自己实现它,该算法非常简单.这是一个有效的例子:

生成随机32位盐:

CA D5 08 9B

使用密码的UTF-8表示(在本例中为"simon")连接:

CA D5 08 9B 73 69 6D 6F 6E

拿MD5哈希:

CB 37 02 72 AC 5D 08 E9 B6 99 4A 17 2B 5F 57 12

再次连接盐:

CA D5 08 9B CB 37 02 72 AC 5D 08 E9 B6 99 4A 17 2B 5F 57 12

并转换为base64编码:

ytUIm8s3AnKsXQjptplKFytfVxI =

您应该能够修改代码以遵循此过程

  • 感谢Derick,它就像一个魅力.给未来读者的建议:它并不总是MD5,它取决于在rabbitmq.config上配置的内容(自v3.6.0起默认为SHA256) (6认同)

Luk*_*ken 11

注意:从 RabbitMQ 开始,3.11.8您可以使用这些方法根据当前配置的密码哈希算法生成哈希密码:

  • rabbitmqctl hash_password foobar
  • curl -u api_user:api_pass rabbitmq-server:15672/api/auth/hash_password/foobar

每个的输出:

$ rabbitmqctl hash_password foobar
Will hash password foobar
c9KkB60KtKFwksRUg3EBYzRCG7Te5l4t4PLaM/7D0DoTdxiZ

$ curl -4su guest:guest -X GET localhost:15672/api/auth/hash_password/foobar
{"ok":"erB0SI9prHWeqeHwcUFdJPziTYn4ZCcepfAFY7XWsjfN70Ln"}
Run Code Online (Sandbox Code Playgroud)


Tod*_*ons 8

这是我前段时间偶然发现的一个小的 python 脚本(属性在脚本中),它非常适合快速生成哈希。它不做任何错误检查,所以很简单:

#!/usr/bin/env python3

# rabbitMQ password hashing algo as laid out in:
# http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-May/012765.html

from __future__ import print_function
import base64
import os
import hashlib
import struct
import sys

# This is the password we wish to encode
password = sys.argv[1]

# 1.Generate a random 32 bit salt:
# This will generate 32 bits of random data:
salt = os.urandom(4)

# 2.Concatenate that with the UTF-8 representation of the plaintext password
tmp0 = salt + password.encode('utf-8')

# 3. Take the SHA256 hash and get the bytes back
tmp1 = hashlib.sha256(tmp0).digest()

# 4. Concatenate the salt again:
salted_hash = salt + tmp1

# 5. convert to base64 encoding:
pass_hash = base64.b64encode(salted_hash)

print(pass_hash.decode("utf-8"))
Run Code Online (Sandbox Code Playgroud)


Wal*_*ldo 5

对于懒惰的人(例如我;)),存在用于框架.Net Core的带有Sha512的RabbitMq密码计算代码。

public static class RabbitMqPasswordHelper
{
    public static string EncodePassword(string password)
    {
        using (RandomNumberGenerator rand = RandomNumberGenerator.Create())
        using (var sha512 = SHA512.Create())
        {
            byte[] salt = new byte[4];

            rand.GetBytes(salt);

            byte[] saltedPassword = MergeByteArray(salt, Encoding.UTF8.GetBytes(password));
            byte[] saltedPasswordHash = sha512.ComputeHash(saltedPassword);

            return Convert.ToBase64String(MergeByteArray(salt, saltedPasswordHash));
        }
    }

    private static byte[] MergeByteArray(byte[] array1, byte[] array2)
    {
        byte[] merge = new byte[array1.Length + array2.Length];
        array1.CopyTo(merge, 0);
        array2.CopyTo(merge, array1.Length);

        return merge;
    }
}
Run Code Online (Sandbox Code Playgroud)


met*_*ker 5

以防万一,接下来应该是 Waldo 的完整代码

//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Text;

namespace Rextester
{
    public static class RabbitMqPasswordHelper
{
    public static string EncodePassword(string password)
    {
        using (RandomNumberGenerator rand = RandomNumberGenerator.Create())
        using (var sha256 = SHA256.Create())
        {
            byte[] salt = new byte[4];

            rand.GetBytes(salt);

            byte[] saltedPassword = MergeByteArray(salt, Encoding.UTF8.GetBytes(password));
            byte[] saltedPasswordHash = sha256.ComputeHash(saltedPassword);

            return Convert.ToBase64String(MergeByteArray(salt, saltedPasswordHash));
        }
    }

    private static byte[] MergeByteArray(byte[] array1, byte[] array2)
    {
        byte[] merge = new byte[array1.Length + array2.Length];
        array1.CopyTo(merge, 0);
        array2.CopyTo(merge, array1.Length);

        return merge;
    }
}

    public class Program
    {
        public static void Main(string[] args)
        {
            //Your code goes here
            Console.WriteLine(Rextester.RabbitMqPasswordHelper.EncodePassword("MyPassword"));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在http://rextester.com/上在线运行它。程序的输出将包含您的哈希值。


Python 版本,作者:christianclinton ( https://gist.github.com/christianclinton/faa1aef119a0919aeb2e )

#!/bin/env/python
import hashlib
import binascii

# Utility methods for generating and comparing RabbitMQ user password hashes.
#
# Rabbit Password Hash Algorithm:
# 
# Generate a random 32 bit salt: 
# CA D5 08 9B 

# Concatenate that with the UTF-8 representation of the password (in this 
# case "simon"): 
# CA D5 08 9B 73 69 6D 6F 6E 

# Take the MD5 hash: 
# CB 37 02 72 AC 5D 08 E9 B6 99 4A 17 2B 5F 57 12 

# Concatenate the salt again: 
# CA D5 08 9B CB 37 02 72 AC 5D 08 E9 B6 99 4A 17 2B 5F 57 12 

# And convert to base64 encoding: 
# ytUIm8s3AnKsXQjptplKFytfVxI= 
# 
# Sources:
# http://rabbitmq.1065348.n5.nabble.com/Password-Hashing-td276.html
# http://hg.rabbitmq.com/rabbitmq-server/file/df7aa5d114ae/src/rabbit_auth_backend_internal.erl#l204 

# Test Case:
#   print encode_rabbit_password_hash('CAD5089B', "simon")
#   print decode_rabbit_password_hash('ytUIm8s3AnKsXQjptplKFytfVxI=')
#   print check_rabbit_password('simon','ytUIm8s3AnKsXQjptplKFytfVxI=')

def encode_rabbit_password_hash(salt, password):
    salt_and_password = salt + password.encode('utf-8').encode('hex')
    salt_and_password = bytearray.fromhex(salt_and_password)
    salted_md5 = hashlib.md5(salt_and_password).hexdigest()
    password_hash = bytearray.fromhex(salt + salted_md5)
    password_hash = binascii.b2a_base64(password_hash).strip()
    return password_hash

def decode_rabbit_password_hash(password_hash):
    password_hash = binascii.a2b_base64(password_hash)
    decoded_hash = password_hash.encode('hex')
    return (decoded_hash[0:8], decoded_hash[8:])

def check_rabbit_password(test_password, password_hash):
    salt, hash_md5sum = decode_rabbit_password_hash(password_hash)
    test_password_hash = encode_rabbit_password_hash(salt, test_password)
    return test_password_hash == password_hash
Run Code Online (Sandbox Code Playgroud)

玩得开心!


小智 5

这是该脚本在 bash 中的一个版本,可在带有 openSSL 的 BusyBox 上运行

#!/bin/bash

function get_byte()
{
    local BYTE=$(head -c 1 /dev/random | tr -d '\0')

    if [ -z "$BYTE" ]; then
        BYTE=$(get_byte)
    fi

    echo "$BYTE"
}

function encode_password()
{
    BYTE1=$(get_byte)
    BYTE2=$(get_byte)
    BYTE3=$(get_byte)
    BYTE4=$(get_byte)

    SALT="${BYTE1}${BYTE2}${BYTE3}${BYTE4}"
    PASS="$SALT$1"
    TEMP=$(echo -n "$PASS" | openssl sha256 -binary)
    PASS="$SALT$TEMP"
    PASS=$(echo -n "$PASS" | base64)
    echo "$PASS"
}

encode_password $1
Run Code Online (Sandbox Code Playgroud)