我正在编写一个由PHP和MySQL驱动的动态站点(在WAMP服务器上运行)。我目前关注的是网站的安全性,但它没有保存任何用户输入,然后输出给任何用户(管理员除外),所以我并不担心XSS。我主要担心的是针对SQL注入攻击和保护管理员登录门户免受彩虹表/暴力破解。
1)将mysql_real_escape_string与sprintf()一起使用可以保护您免受SQL注入吗?如,
$thing = mysql_real_escape_string($_REQUEST['thing'])
$query = sprintf("SELECT * FROM table WHERE thing='%s'", $thing);
$result = mysql_query($query);
这是否足够安全?当然,没有系统是完全安全的,但我知道准备好的语句应该是防止SQL注入的最佳方法。但是,如果我的代码“足够安全”,那么我认为没有理由进行更改。我在某处读到mysql_query默认情况下每次调用只允许一次MySQL查询,出于安全原因,这是正确的吗?如果是这样,我不知道如何对我的代码进行任何注射,但如果我的逻辑存在缺陷,请告诉我。
2)我正在为该网站编写一个管理门户,以便它的所有者可以在网站上以一种简单,用户友好的方式操作MySQL数据库(来自一个未链接到任何地方的登录HTML文件)在网站上)。我对安全性的关注是登录过程,它由两个页面组成。首先,收集用户登录信息:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>Admin Portal</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex, nofollow">
<link rel="stylesheet" type="text/css" href="http://www.anotherdomain.com/my.css">
<script type="text/javascript" src="http://www.anotherdomain.com/my.js"></script>
</head>
<form method="post" action="admin/login.php">
<table align="center">
<tr><th>Admin Login Form</th></tr>
<tr><td>Name</td><td><input type="text" name="Name" size="30" onKeyPress="return aJSFunctionToStopEnterKeyFromWorking(event)"></td></tr>
<tr><td>Password</td><td><input type="password" name="Password" size="30" onKeyPress="return aJSFunctionToStopEnterKeyFromWorking(event)"></td></tr>
<tr><td></td><td><input type="reset" value="Clear Form"> <input type="submit" value="Login"></td></tr>
</table>
</form>
其次,实际登录脚本:
<?php
$inputusername = $_POST['Name'];
$inputpassword = $_POST['Password'];
$username = "a username that is not obvious";
$password = "a password that is at least 10 characters long";
$salt = hash('sha512', "a messed up string with weird characters that I wrote");
$hashword = hash('sha512', $password . $salt);
$inputhashword = hash('sha512', $inputpassword . $salt);
if($username == $inputusername && $hashword == $inputhashword) {
session_start();
$_SESSION['valid'] = 1;
header('Location: portal.php');
exit;
}
else {echo "Invalid username or password";}
?>
然后在登录过程之后,每个页面都将具有以下内容以确保管理员已登录:
<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>
Portal page goes here
由于没有新用户的创建,因此门户网站只会有一个用户。我只是想知道这种登录方法对彩虹表和暴力强制等攻击有多安全?我假设,因为我使用了非常大的hashword和salt,所以即使用户名已经知道了,也应该对这些类型的攻击非常安全。
我也想知道这是否对会话劫持是安全的,因为这是我听到的一个术语,但我不太了解...我知道我不会抛出会话ID或者这样的事情,所以看起来很安全。
3)我应该知道/想到的任何其他安全问题?
我真的很感激我得到的任何帮助!
答案 0 :(得分:1)
要考虑的其他要点:
<强> 1。你很容易受到暴力侵害
字典攻击会破解您的密码。由于绝大多数用户的密码不安全,因此只是时间问题。使用验证码或记录无效条目。或者在密码不正确时添加一些延迟。
正如Shrapnel上校所说,彩虹表并不是你所关心的问题,因为当有人有一堆哈希并希望破解它们时会使用彩虹表。盐被用来获得对彩虹桌的一些保护,这不是你的情况。
<强> 2。您以明文形式发送密码
如果有人嗅到您的登录信息(例如,wifi),那么您注定要失败。有一些javascript库可以使用公钥加密任何东西。如果您不想使用SSL,请加密登录/密码,发送到服务器,使用私钥解密,这样您就更安全了。
第3。考虑在MySQL上使用预准备语句
使用预准备语句有助于防止SQL注入,因为它甚至可以安全地运行恶意输入:
$dbc = new mysqli("mysql_server_ip", "mysqluser", "mysqlpass", "dbname");
$statement = $db_connection->prepare("SELECT * FROM table WHERE thing='?'");
$statement->bind_param("i", $thing);
$statement->execute();
<强> 4。不要在客户端验证中继
在您的登录表单上,您继续使用javascript函数阻止Enter键生效。如果我禁用Javascript怎么办?您可以使用隐藏字段(例如&lt; input type ='hidden'name ='FormIsValid'value ='0'&gt;),使用您的函数来阻止Enter键,并使用onSubmit()函数将FormIsValid更改为1在发送表格之前。在您的服务器中,验证FormIsValid。
<强> 5。您很容易受到会话劫持
您的会话保存在Cookie中,默认名称为PHPSESSID。如果攻击者可以获得该cookie,它可以将其发送到您的服务器并窃取您的会话。要防止它,您可以在会话中保存用户IP地址和用户代理,并比较每个请求从会话收到的值。如果值不匹配,则用户IP可能已更改或会话可能已被劫持。
<强> 6。您可能容易受到会话固定的影响
如上所述,如果有人说服您的管理员访问某个网站,并且此网站会根据请求向您的网站发送带有PHPSESSID的请求,那么您的网站会创建会话,处理登录名/密码,并说明凭证是错误的。直到现在还不错。
稍后,您的管理员会登录您的门户网站,会话已存在,登录名和密码匹配,会话已更新。变量有效现在为1。
一旦变量更新,攻击者就可以完全访问您的门户,因为他知道PHPSESSID,您的站点不会阻止会话劫持或会话固定。
要避免会话固定和劫持,请参阅#5。
答案 1 :(得分:0)
1)将mysql_real_escape_string与sprintf()一起使用可以保护您免受SQL注入吗?
只要1)您将此功能仅应用于字符串,并且2)设置了使用mysql_set_charset()
的正确编码。
对于数字,您只需使用%d
我在某处读到mysql_query默认情况下每次调用只允许一次MySQL查询,出于安全原因,这是正确的吗?
你是对的。安全性不大,但设计更有可能。
如果是这样,我不知道如何对我的代码进行任何注射,但如果我的逻辑存在缺陷,请告诉我。
你错了。 SQL注入代表在查询中注入SQL代码,而不仅仅是单个“bobby drop tables”查询。
我只是想知道这种登录方法对彩虹表和暴力强制等攻击有多安全?
彩虹桌与此无关,而强暴仍然是一种危险 我不认为这是一个大问题。不比以纯文本发送密码大。
我假设因为我使用了非常大的hashword和salt,所以它应该是非常安全的
这里有趣的一点。
事实上,所有散乱/腌制混乱在这里完全没用。它比仅仅比较普通密码更安全。
我也想知道这是否对会话劫持是安全的,
总有可能。如果你担心这么多,请使用SSL连接,就像google mail一样。
所以我并不担心XSS。
这是非常错误的感觉
就像echo "Requested article: ".$_GET['id']'
一样简单,事情已经很脆弱了。
答案 2 :(得分:0)
看起来其他人已经把它分开了。但我还要补充一点:
身份验证绕过:
<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>
执行header("location: ...")
脚本仍然执行时,您仍需exit
或die()
。事实上,通过这段代码,我知道所有页面都可以由未经身份验证的用户访问。
答案 3 :(得分:0)
更多改进:
检查参数类型 之前引用它们。 (除了文本搜索。这需要更多)。丢失的值可能会引发攻击者可以学习的SQL错误;)
将一个反csrf令牌放入您的登录页面,并在登录错误后暂停,以防止暴力攻击。
通过 https 登录。通过http,您可以通过网络推送清除密码。在中间攻击场景中的完美男人(但这很难做到:)。
检查输入编码是否正确。有一些UTF-7攻击使用日语多字节字符,单字符号作为第二个字节。 (这可能会破坏mysql_real_escape_string)Veeery棘手的东西。
使用准备好的陈述