这个字符串是Base64吗?我怎么知道使用了什么编码?
这对我来说是个难题,我真的很烦恼自己无法解决它!所以,如果有人有空,我希望能听到一些解决的建议!
我使用的软件会把密码存储在一个Oracle数据库里。密码字段的类型是Varchar2(100 char)。我觉得这个软件会对密码进行编码,然后把编码后的字符串存储在数据库中。
我的密码是'1234',而编码后的字符串是'cRDtpNCeBiql5KOQsKVyrA0sAiA='。数据库里的所有密码都是28个字符长。
我给自己设定的难题是找出这个字符串的编码和/或加密方式。我首先检查了Base64。
这是我在Python(idle)中的第一次测试:
>>> import base64
>>> encoded = 'cRDtpNCeBiql5KOQsKVyrA0sAiA='
>>> decoded = base64.b64decode(encoded)
>>> decoded
'q\x10\xed\xa4\xd0\x9e\x06*\xa5\xe4\xa3\x90\xb0\xa5r\xac\r,\x02 '
>>> print decoded
qíᄂО*ᆬ䣐ᄚᆬrᆲ
,
这是我的第二次测试:
>>> myString = '1234'
>>> encoded = base64.b64encode(myString)
>>> encoded
'MTIzNA=='
>>> decoded = base64.b64decode('MTIzNA==')
>>> decoded
'1234'
所以,我的第一个想法是这不是Base64编码。查了一下维基百科(https://en.wikipedia.org/wiki/Base64),似乎Base64编码的字符串并不是固定大小的。我的第二个想法是这个字符串可能是先被加密,然后再编码成Base64的,这就是为什么我得到的解码字符串看起来很奇怪。
有什么想法吗?
2 个回答
当 len(decoded) = 20
时,我猜这可能是经过Base64编码的SHA1哈希值。
你可以通过以下方式创建这样的密码:
import hashlib
import base64
passwd = '1234'
hp = base64.b64encode(hashlib.sha1(passwd).digest())
print hp
print len(hp)
至于存储密码的方式,这并不是很好,因为很多破解者可以使用“彩虹表”,这些表里存储了预先计算好的MD5、SHA1和其他哈希值,他们可以根据这些哈希值找出密码。为了防止这种情况,应该使用“盐”:hash(salt+passwd)
,这个盐可以是一个随机字符串,存储在数据库中,每个用户都有一个,或者比如说用户的登录名(一些永远不会改变的东西)。
其实这是经过Base64编码的。不过,编码的不是密码本身,而是它的SHA-1哈希值。
from sha import sha
print 'cRDtpNCeBiql5KOQsKVyrA0sAiA='.decode('base64').encode('hex')
print sha('1234').hexdigest()
或者对于更新版本的Python:
from hashlib import sha1
print 'cRDtpNCeBiql5KOQsKVyrA0sAiA='.decode('base64').encode('hex')
print sha1('1234').hexdigest()
Base64会把3个字节编码成4个字符。你有27个字符,加上一个填充字符,可以看出这实际上是20个编码字节(27*3/4
)。当某个与安全相关的东西是20个字节(或者160位)长的时候,通常就是SHA-1。而如果是16个字节(128位),那通常是MD5。
顺便说一下,给密码加点随机的“盐”是个好主意,这样即使两个密码是一样的,在数据库里也不会显得特别突出。在Linux系统中,crypt
模块可以帮你做到这一点,并且还会增加一些额外的安全措施。
编辑:回应另一个评论 - 从“加密”的密码中找回原始密码是非常简单的。有一种技术几年前变得很有名,叫做彩虹表。甚至还有一些在线版本。只需输入你的哈希值(以十六进制形式,如7110eda4d09e062aa5e4a390b0a572ac0d2c0220
),它就会在一秒钟内给你1234
。