Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Security 在数据库中加密/散列纯文本密码_Security_Encryption_Passwords_Security By Obscurity - Fatal编程技术网

Security 在数据库中加密/散列纯文本密码

Security 在数据库中加密/散列纯文本密码,security,encryption,passwords,security-by-obscurity,Security,Encryption,Passwords,Security By Obscurity,我继承了一个web应用,我刚刚发现它在SQL Server数据库中以纯文本形式存储了超过300000个用户名/密码。我意识到这是一件非常糟糕的事情™. 知道我必须更新登录和密码更新过程以进行加密/解密,并且对系统其余部分的影响最小,您认为从数据库中删除纯文本密码的最佳方法是什么 感谢您的帮助 编辑:对不起,如果我不清楚的话,我是想问你加密/散列密码的过程是什么,而不是具体的加密/散列方法。 我是否应该: 对数据库进行备份 更新登录/更新密码 几个小时后,检查用户表中的所有记录,对密码进行哈希运算

我继承了一个web应用,我刚刚发现它在SQL Server数据库中以纯文本形式存储了超过300000个用户名/密码。我意识到这是一件非常糟糕的事情™.

知道我必须更新登录和密码更新过程以进行加密/解密,并且对系统其余部分的影响最小,您认为从数据库中删除纯文本密码的最佳方法是什么

感谢您的帮助

编辑:对不起,如果我不清楚的话,我是想问你加密/散列密码的过程是什么,而不是具体的加密/散列方法。

我是否应该:

  • 对数据库进行备份
  • 更新登录/更新密码
  • 几个小时后,检查用户表中的所有记录,对密码进行哈希运算并替换每个记录
  • 测试以确保用户仍然可以登录/更新密码

  • 我想我更关心的是用户的数量,所以我想确保我做得正确。

    用md5散列它们。密码通常就是这么做的。

    正如其他人所提到的,如果你能帮上忙,你就不想解密。标准的最佳实践是使用单向散列进行加密,然后在用户登录时对其密码进行散列以进行比较


    否则,您必须使用强加密来加密,然后解密。只有在政治原因强烈的情况下,我才建议这样做(例如,您的用户习惯于能够打电话到帮助台检索他们的密码,而您有来自高层的强大压力,不允许更改密码)。在这种情况下,我将从加密开始,然后开始构建一个业务案例以转移到散列

    我想您必须在数据库中添加一列加密密码,然后在所有记录上运行批处理作业,获取当前密码并对其进行加密(正如其他人提到的,像md5这样的散列是相当标准的编辑:但不应单独使用-请参阅其他答案以获得良好的讨论),将其存储在新列中,并检查所有操作是否顺利进行

    然后,您需要更新前端,以便在登录时对用户输入的密码进行散列,并验证是否与存储的散列一致,而不是检查明文与明文

    在我看来,在最终删除所有明文密码之前,将这两列保留一段时间以确保没有任何可疑的事情发生,这似乎是明智的做法

    也不要忘记,只要密码被访问,代码就必须更改,例如密码更改/提醒请求。当然,你会失去通过电子邮件发送忘记密码的能力,但这并不是坏事。您将不得不使用密码重置系统

    编辑: 最后一点,您可能要考虑避免我在试题安全登录网站第一次尝试时犯的错误:


    处理用户密码时,考虑散列发生的位置。在我的例子中,散列是由运行在Web服务器上的PHP代码计算的,但是密码是以明文形式从用户的机器传输到页面的!这在我工作的环境中还行(ish),因为它在https系统中(uni网络)。但是,在现实世界中,我认为您可能希望在密码离开用户系统之前,使用javascript等对其进行散列,然后将散列传输到您的站点。

    要对密码进行散列,您可以使用该函数。返回一个varbinary,因此必须创建一个新列,然后删除旧的varchar列

    然后使用如下查询修改代码以验证密码

    SELECT count(*) from users WHERE hashedPassword = 
    HashBytes('SHA1',salt + '|' + <password>)
    
    从hashedPassword=
    HashBytes('SHA1',salt+'|'+)
    

    其中是用户输入的值。

    出于身份验证目的,您应该避免使用可逆加密存储密码,即,您应该只存储密码哈希,并根据存储的哈希检查用户提供的密码的哈希。然而,这种方法有一个缺点:如果攻击者掌握了您的密码存储数据库,它很容易受到攻击

    您应该做的是存储预先选择(和秘密)的salt值+密码的散列。也就是说,连接salt和密码,散列结果,并存储该散列。进行身份验证时,请执行相同的操作-将您的salt值与用户提供的密码、哈希连接起来,然后检查是否相等。这使得彩虹表攻击不可行


    当然,如果用户通过网络发送密码(例如,如果您正在处理web或客户机服务器应用程序),那么您不应该通过网络发送明文密码,因此您应该存储哈希(salt+密码),并根据哈希(salt+哈希(密码))进行检查,并让您的客户端对用户提供的密码进行预哈希,然后通过网络发送该密码。如果用户(和许多用户一样)出于多种目的重复使用同一密码,这也可以保护用户的密码。

    与所有安全决策一样,存在权衡。如果对密码进行哈希运算(这可能是最简单的操作),则无法提供返回原始密码的密码检索功能,您的员工也无法查找个人密码以访问其帐户

    您可以使用对称加密,这有其自身的安全缺陷。(如果服务器受损,对称加密密钥也可能受损)

    您可以使用公钥加密,并在单独的计算机上运行密码检索/客户服务,该计算机与web应用程序隔离存储私钥。这是最安全的,但需要两台机器的体系结构,可能中间还要有防火墙。

    接下来请将当前密码列保留一段时间,以便在出现问题时可以快速、轻松地回滚

    就加密密码而言:
    SELECT count(*) from users WHERE hashedPassword = 
    HashBytes('SHA1',salt + '|' + <password>)
    
    from hashlib import sha256
    from hmac import HMAC
    import random
    
    def random_bytes(num_bytes):
      return "".join(chr(random.randrange(256)) for i in xrange(num_bytes))
    
    def pbkdf_sha256(password, salt, iterations):
      result = password
      for i in xrange(iterations):
        result = HMAC(result, salt, sha256).digest() # use HMAC to apply the salt
      return result
    
    NUM_ITERATIONS = 5000
    def hash_password(plain_password):
      salt = random_bytes(8) # 64 bits
    
      hashed_password = pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)
    
      # return the salt and hashed password, encoded in base64 and split with ","
      return salt.encode("base64").strip() + "," + hashed_password.encode("base64").strip()
    
    def check_password(saved_password_entry, plain_password):
      salt, hashed_password = saved_password_entry.split(",")
      salt = salt.decode("base64")
      hashed_password = hashed_password.decode("base64")
    
      return hashed_password == pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)
    
    password_entry = hash_password("mysecret")
    print password_entry # will print, for example: 8Y1ZO8Y1pi4=,r7Acg5iRiZ/x4QwFLhPMjASESxesoIcdJRSDkqWYfaA=
    check_password(password_entry, "mysecret") # returns True
    
    >>> fsh = fshp.crypt('OrpheanBeholderScryDoubt')
    >>> print fsh
    {FSHP1|8|4096}GVSUFDAjdh0vBosn1GUhzGLHP7BmkbCZVH/3TQqGIjADXpc+6NCg3g==
    >>> fshp.validate('OrpheanBeholderScryDoubt', fsh)
    True
    
    >>> fsh = fshp.crypt('ExecuteOrder66', saltlen=2, rounds=10, variant=0)
    >>> print fsh
    {FSHP0|2|10}Nge7yRT/vueEGVFPIxcDjiaHQGFQaQ==
    
    def random_bytes(num_bytes):
        return os.urandom(num_bytes)