我在这里错过了任何 vulns 吗?

信息安全 密码 Web应用程序 爪哇
2021-08-27 19:29:47

我最近在一次安全工程师的面试中受到了打击,但我没有得到任何关于我的表现的具体反馈。我想向社区重新提出这个问题,以便我可以完善这些元素。我发现的漏洞列表如下。

您在一个登录页面,两个表单元素用户:/密码:您的用户名是彼得。

成功登录应用程序后,您将被定向到显示 Hello 'Peter' 的页面。(此页面上“Peter”的来源来自登录用户名表单中填充的用户变量)

通用代码如下:

public String login( String user, String pass ) { 
       if (pass == DB.lookup(user)){ 
            return "Hello " + user; 
           }
       else { .....} 
       } 
  1. 此示例登录应用程序中存在哪些漏洞?

  2. 你会如何修复它们?

  3. 您将如何存储您的密码?

  4. 如果您以这种方式存储它们,您通过什么机制恢复密码以根据用户在密码表单中键入的内容来验证它?

    这是我到目前为止所看到的:

XSS:用户输入(用户)在不经过编码库或验证器的情况下被推送到响应的 jsp 页面这一事实意味着您拥有。

修复:我会将 OWASP java 编码器项目中的 sanitizer 实现到 HTML 元素中。

我会使用 bcrypt 将密码存储为加盐哈希。每个散列密码的唯一盐。

3个回答

还没有人明确提到存在 SQL 注入的可能性。用户字符串需要适当的验证以确保其存在并且仅包含有效的用户名。

如果没有看到服务器上的代码,我不能 100% 确定。特别是因为我不知道是什么DB.lookup()据我所知,它可以处理许多这样的安全问题。

public String login( String user, String pass ) { 
   if (pass == DB.lookup(user)){ 
        return "Hello " + user; 
       }
   else { .....} 
   } 

此示例登录应用程序中存在哪些漏洞?你会如何修复它们?

  1. 尝试通过 IP/cookie 登录没有超时,用户也没有超时。轻松允许拒绝服务(甚至 DDoS)攻击蛮力攻击。
  2. 没有确认是否userpass为空,因此适当的长度,并以正确的格式对数据库进行检查。如果页面返回错误,并允许您通过反复试验尝试找出更多信息怎么办?
  3. 可能的 SQL 注入攻击DB.lookup(user),但也有可能DB.lookup()处理此问题。
  4. return "Hello " + user;同样,由于没有适当的检查,您可以将其用于服务器页面中的inject 任何内容这意味着你可以运行流氓ASP/ JSP/ PHP/whatever代码。
  5. 同样,没有看到DB.lookup()代码,我无法判断它的作用,但我可以做出假设。你似乎是比较passusername.这可能意味着你可以尝试登录的密码是相同的用户名,并用它来登录,无需密码。您可以使用 登录login("Jake", "Jake");,它会工作。

您将如何存储您的密码?

在数据库中,用户不应该访问任何东西,使用bcrypt/ hashed+ salted(显然是唯一的)+ 可靠的SlowEquals()密码。正确实现的SlowEquals/XOR将防止侧信道定时攻击。

如果您以这种方式存储它们,您通过什么机制恢复密码以根据用户在密码表单中键入的内容来验证它?

检查密码输入是否不为空,是否具有适合密码的长度,并且不包含不允许的字符。最多尝试三次。您检查加盐哈希是否与密码相对应。

关于userand pass,您必须检查它们是否不为空,是否具有数据库中每个字段的适当长度,以及它们的格式是否正确。要检查正确的格式,您可以使用正则表达式来确保它是带有正确符号的字母数字。或者您可以删除所有未使用的字符。

并且不要忘记,您需要同时测试用户名和密码,DB.lookup()否则您可以使用用户的用户名作为密码登录!可怕!

更安全的代码可能看起来像这样(未经测试的伪代码,顺便说一句)

DB的伪类:

public static class DB
{
     public static boolean lookup(string u, string p)
     {
          // Test salted hash against the user's hash for that particular username.
          return (encryption.testPassword(p, getUsersHashedPassWord(u))) ? true : false;
     }
}

错误检查伪代码:

private boolean properLength(String u, String p)
{
     return ((u.length > 3 && u.length <= 12) && (p.length > 8 && p.length <= 30)) ? true : false;
}

private boolean properFormat(String u, String p)
{
    return (regex.Valid(u, usernameRegex) && regex.Valid(p, passwordRegex)) ? true : false; 
}

private String stripBadStuff(String stuff)
{
    // Just in case or something...
    return EncodingFunction.ToASCII(stuff).regexReplace(badCharacaterRegex, ""); 
}



public String login( String user, String pass ) 
{ 
   if (!loginTriesExceeded) // Currently unhandled for example.
   {
       if ((user != null && pass != null) && properLength(user, pass) && properFormat(user, pass))
       {
            // Unhandled for example. This is so they can't change their IP address to continue trying.
            if (!userLoginTriesExceeded)
            {
               String newUser = stripBadStuff(user);
               String newPass = stripBadStuff(pass);
               // Would be changing DB.lookup() to return true if valid login is detected. DB.lookup(newUser,newPass) will now be assumed that it tests the plaintext password against the salted hash. 
               if (DB.lookup(newUser, newPass)) 
               { 
                    // Prevent injection. This will assume DB.lookup() tests the password against the stored hash.
                    return "Hello " + newUser; 
               }
               else 
               {
                    return "Invalid login.";
               }
           }
           else
           {
                return "User login attempts exceeded.";
           }
        }
        else
        {
             return "Invalid login";
        }
    }
    else
    {
        // Do nothing, or inform the user that they've exceeded max logins.
        return null; // So all code paths return a value. 
    }
} 

请记住,这是未经测试的伪代码。我可能错过了一些事情。

我可以看到的漏洞:

  1. 在这里,它可能不算作漏洞(因此),但密码似乎没有在该代码中进行哈希处理。
  2. 使用 == 进行字符串比较容易受到统计时序分析的影响。
  3. 你找到的 XSS。
  4. 我假设 DB.lookup 可以安全地像这样使用而不会出现 SQL 注入漏洞。正如@SourLolita 所指出的,仍然缺少错误处理。
  5. 似乎没有任何 XSRF 保护,至少在该代码中不可见。在这种情况下,我不知道如何利用它。

如何修复它们:

  1. 使用密码哈希算法(如 bcrypt 或 scrypt)对密码进行哈希处理。
  2. 使用密码散列库比较/检查功能。
  3. 通过希望由正在使用的框架提供的适当转义函数传递名称。
  4. 添加错误检查。如果用户名是秘密的,那么这里也适用时间免疫,然后会很复杂。
  5. 我将不得不阅读。有一阵子了。一种方法是将特殊的随机令牌与表单一起提交并作为 cookie 并要求它们匹配。