首页 > 解决方案 > 在没有 Python 的情况下生成 Jupyter Notebook 密码

问题描述

https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html#docker-options之后,您可以定义自己的密码,以便在使用 docker 映像时启动 Jupyter Notebook。

docker run -d -p 8888:8888 jupyter/base-notebook start-notebook.sh --NotebookApp.password='sha1:74ba40f8a388:c913541b7ee99d15d5ed31d4226bf7838f83a50e'

我只能发现使用IPython.lib.passwd()可以生成使用过的salted sha1密码。但是,如何在不使用 Python 的情况下生成它?我没有 IPython,或者可能只是不知道如何使用它。我在 CentOS Stream 上。

标签: bashjupyter-notebookjupytersha1salt

解决方案


您可以使用以下小 shell 脚本来近似原始密码生成算法:

#!/bin/bash

passphrase="hello, world"

# generate salt
salt=$(openssl rand -hex 6)

# generate hash
algorithm=sha1
echo -n "$(echo ${passphrase} | iconv -t utf-8)${salt}" | openssl dgst -${algorithm} | awk -v alg="${algorithm}" -v salt="${salt}" '{print alg ":" salt ":" $NF}'

为什么这行得通(有点)?

您提到原始密码生成算法是基于IPython.lib.passwdIPython.lib.security. 相关的代码部分是:

salt_len = 12

h = hashlib.new(algorithm)
salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
h.update(encode(passphrase, 'utf-8') + encode(salt, 'ascii'))

return ':'.join((algorithm, salt, h.hexdigest()))

为了理解这段代码的作用,首先再次查看生成的输出很有用。根据您的问题,我们有一个生成密码的示例:

sha1:74ba40f8a388:c913541b7ee99d15d5ed31d4226bf7838f83a50e

冒号将此字符串分为三部分:

<hashing-algorithm> : <salt> : <hashed salted passphrase>

考虑到这一点,让我们看一下IPython代码。在顶部,我们定义了用于盐的字符数。让我们仔细检查一下-是的,确实,在您的示例中,盐由 12 个字符组成:74ba40f8a388.

接下来,h创建散列算法的新实例。从您的示例中我们知道,algorithm参数的值为"sha1"

之后,生成随机盐。现在这条线很有趣。如果您没有 Python 背景,百分号 ( %) 可能会让您想起整数模运算符。但实际上并非如此,因为百分号左边的参数是string. 所以,相反,这是(现在有点过时的printf)用于格式化字符串的 Python 语法,与in非常相似C,除了您不限于在 Python 中打印,您可以在任何有字符串的地方使用此格式化操作。

鉴于我们知道salt_len12,这条线基本上简化为:

salt = '%012x' % random.getrandbits(48)

这意味着盐应该是一个 48 位的位串,格式为 12 位十六进制字符串。

为什么是 48 位?好吧,你需要两个十六进制字符来编码一个字节(0x00通过0xff),所以如果我们的目标是 12 个字符,我们需要 6 个字节 = 48 位。

前面的最后一行returnsha1算法应用于 utf-8 编码的密码短语和 ascii 编码的 salt 的串联。

最后,算法、盐和散列加盐密码作为连接字符串返回,冒号 ( :) 作为分隔符。

现在,如果您检查我在上面发布的 shell 脚本,您会发现其中或多或少相同的步骤。但是有一个显着的区别,这就是为什么我最初写它只是实际算法的近似值。

不同之处在于盐的生成方式。虽然结果在这两种情况下都是 12 位十六进制字符串,但IPython代码使用Mersenne-Twister的实现,而我的脚本基于MD5散列。这将导致不同的加密属性。

但是你可以自己决定是否可以接受。不幸的是,我无法从命令行获取 Mersenne Twister 的实现。但是,如果您知道生成 salt 的好方法,请随时更新脚本。它的其余部分不应受到影响。


或者,如果您更喜欢没有openssl的解决方案,您也可以使用此版本:

#!/bin/bash

passphrase="hello, world"

# generate salt
salt=$(tr -dc a-f0-9 < /dev/urandom | head -c 12)

# generate hash
algorithm=sha1
echo -n "$(echo ${passphrase} | iconv -t utf-8)${salt}" | sha1sum | awk -v alg="${algorithm}" -v salt="${salt}" '{print alg ":" salt ":" $1}'

但不幸的是,我无法说明通过/dev/urandom这种方式生成的盐的特性。


推荐阅读