如果没有看到服务器上的代码,我不能 100% 确定。特别是因为我不知道是什么DB.lookup()。据我所知,它可以处理许多这样的安全问题。
public String login( String user, String pass ) {
if (pass == DB.lookup(user)){
return "Hello " + user;
}
else { .....}
}
此示例登录应用程序中存在哪些漏洞?你会如何修复它们?
- 尝试通过 IP/cookie 登录没有超时,用户也没有超时。轻松允许拒绝服务(甚至 DDoS)攻击和蛮力攻击。
- 没有确认是否
user或pass为空,因此适当的长度,并以正确的格式对数据库进行检查。如果页面返回错误,并允许您通过反复试验尝试找出更多信息怎么办?
- 可能的 SQL 注入攻击
DB.lookup(user),但也有可能DB.lookup()处理此问题。
return "Hello " + user;同样,由于没有适当的检查,您可以将其用于服务器页面中的inject 任何内容。这意味着你可以运行流氓ASP/ JSP/ PHP/whatever代码。
- 同样,没有看到
DB.lookup()代码,我无法判断它的作用,但我可以做出假设。你似乎是比较pass到username.这可能意味着你可以尝试登录的密码是相同的用户名,并用它来登录,无需密码。您可以使用 登录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.
}
}
请记住,这是未经测试的伪代码。我可能错过了一些事情。