动态网站安全问题(PHP+MySQL)

发布于 2024-10-31 21:43:37 字数 3095 浏览 0 评论 0原文

我正在编写一个由 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

由于没有创建新用户,因此只会有成为门户网站的用户之一。我只是想知道这种登录方法对于彩虹表和暴力破解等攻击的安全性如何?我认为,由于我将哈希词和盐设置得非常大,因此即使用户名以某种方式已知,它也应该非常安全地免受此类攻击。

我还想知道这是否可以避免会话劫持,因为这是一个我听说过的术语,但我不太了解......我知道我从来没有乱扔会话 ID 或类似的东西,所以看起来很安全。

3)我应该了解/考虑的任何其他安全问题?

我真的很感谢我在这方面得到的任何帮助!

I'm writing a dynamic site that is powered by PHP and MySQL (to be run on a WAMP server). My current concerns are about the security of the site, however it does not feature any user input being saved and then later output for any users (except by admins), so I'm not really worried about XSS. My main concerns are against SQL injection attacks and protecting an admin login portal against rainbow tables/brute forcing.

1) Does using mysql_real_escape_string in conjunction with sprintf() protect you from SQL injection? e.g.,

$thing = mysql_real_escape_string($_REQUEST['thing'])
$query = sprintf("SELECT * FROM table WHERE thing='%s'", $thing);
$result = mysql_query($query);

Is this sufficiently safe? Of course, no system is perfectly safe, but I know that prepared statement are supposed to be the best way to protect against SQL injection. However, if my code is "safe enough" then I see no reason to make the change over. I read somewhere that mysql_query only allows one MySQL query per call for security reason by default, is that correct? If so, I don't see how any injections could be done on my code, but please let me know if there is a flaw in my logic here.

2) I am writing an admin portal for the site so that the owners of it can manipulate the MySQL database in an easy, user-friendly way on the website (from a login HTML file that isn't linked to from anywhere on the site). My concern for security here is the login process, which consists of two pages. First, gathering the user login information:

<!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>

Second, the actual login script:

<?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";}
?>

And then after the login process, each page will have the following to ensure that the admin is logged in:

<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>
Portal page goes here

Since there is no creation of new users, there will only ever be one user for the portal. I am just wondering how safe this method of login is against attacks such as rainbow tables and brute forcing? I assume since I made the hashword and salt both very large it should be quite safe from these sorts of attacks, even if the username were somehow a known.

I am also wondering if this is safe from session hijacking, as that is a term I have heard thrown around but I don't know much about... I know that I'm not ever throwing a session ID around or anything like that, so it seems pretty secure.

3) Any other security concerns I should know/think about?

I really appreciate any help I get with this!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云雾 2024-11-07 21:43:37

其他需要考虑的要点:

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 会怎样?您可以使用隐藏字段(例如 ),使用您的函数来阻止 Enter 键,并使用 onSubmit() 函数将 FormIsValid 更改为1 在发送表格之前。在您的服务器中,验证 FormIsValid。

5.您很容易受到会话劫持

您的会话保存在 cookie 中,默认名称为 PHPSESSID。如果攻击者可以获取该 cookie,则可以将其发送到您的服务器并窃取您的会话。为了防止这种情况,您可以将用户 IP 地址和用户代理保存在会话中,并在每次请求时比较从会话收到的值。如果值不匹配,则用户 IP 可能已更改或会话可能已被劫持。

6.您可能容易受到会话固定的攻击

如上所述,如果有人说服您的管理员访问某个网站,并且该网站向您的网站发送请求,并且请求中包含 PHPSESSID,您的网站将创建会话,处理登录名/密码,并指出凭据错误。到现在还不错。

稍后,您的管理员登录到您的门户,会话已存在,登录名和密码匹配,并且会话已更新。变量 valid 现在为 1。

一旦变量更新,攻击者就可以完全访问您的门户,因为他知道 PHPSESSID,您的站点不会阻止会话劫持或会话固定。

为了避免会话固定和劫持,请参阅#5。

Other points to think about:

1. You are vulnerable to bruteforce

A dictionary attack would crack your password. As the vast majority of users have an insecure password, it's only matter of time. Use captcha, or log invalid entries. Or add some delay when the password is incorrect.

As Col. Shrapnel said, a rainbow table isn't a concern to you because they are used when someone have a bunch of hashes and want to crack them. Salt is used to gain some protection against a rainbow table, and this is not your case.

2. You are sending passwords in clear text

If someone sniff your login (wifi, for example), you are doomed. There's some javascript libs which can encrypt anything using public keys. If you don't want to use SSL, encrypt the login/password, send to server, decrypt using the private key, and you are safer.

3. Consider using prepared statements on MySQL

Using prepared statements helps against SQL injection, as it can safely run even with malicious input:

$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. Don't relay on client-side validation

On your login form, you relay on a javascript funcion preventing Enter-key to function. What if I disable Javascript? You could use a hidden field (e.g. < input type='hidden' name='FormIsValid' value='0' >), use your function to prevent Enter-key, AND use an onSubmit() function to change FormIsValid to 1 before sending the form. In your server, verify FormIsValid.

5. You are vulnerable to session hijacking

Your session are saved on a cookie, by default named PHPSESSID. If an attacker can get that cookie, it could send it to your server and steal your session. To prevent it, you can save the user IP address and user agent in the session, and compare the value received from the session on every request. If the values doesn't match, the user IP may have changed or the session may have been hijacked.

6. You can be vulnerable to session fixation

As stated above, if someone convinces your admin to access some site, and this site sends a request to your site with a PHPSESSID on the request, your site would create the session, process the login/password, and state that the credentials are wrong. Not bad until now.

Later, your admin logs into your portal, the session already exists, the login and password matches, and the session is UPDATED. The variable valid now is 1.

As soon as the variable are updated, the attacker have full access to your portal, as he knows the PHPSESSID, your site doesn't prevent session hijacking, or session fixation.

To avoid session fixation and hijacking, see #5.

情话已封尘 2024-11-07 21:43:37

1) 将 mysql_real_escape_string 与 sprintf() 结合使用是否可以防止 SQL 注入?

只要 1) 您仅将此函数应用于字符串,并且 2) 使用 mysql_set_charset() 设置了正确的编码。
对于数字,您可以简单地使用 %d

我在某处读到,出于安全原因,默认情况下 mysql_query 只允许每次调用一个 MySQL 查询,这是正确的吗?

你是对的。安全性并没有多大,但设计上更有可能。

如果是这样,我不知道如何在我的代码上进行任何注入,但请让我知道我的逻辑是否存在缺陷。

您错了。 SQL 注入代表在查询中注入 SQL 代码,而不仅仅是单个“bobby drop table”查询。

我只是想知道这种登录方法对于彩虹表和暴力破解等攻击的安全性如何?

彩虹表在这里没有任何作用,而暴力破解仍然是一种危险。
但我认为这没什么大不了的。不大于以纯文本形式发送密码。

我认为由于我将哈希词和盐都设置得非常大,所以应该非常安全

这里有趣的一点。
事实上,所有这些散列/加盐混乱在这里完全没有用。它并不比仅比较普通密码更安全。

我还想知道这是否可以避免会话劫持,

总有可能。如果您非常担心,请使用 SSL 连接,就像谷歌邮件一样。

所以我并不真正担心 XSS。

这种感觉很错误。
就像echo“请求的文章:”。$_GET['id']'一样简单,事情已经很容易受到攻击。

1) Does using mysql_real_escape_string in conjunction with sprintf() protect you from SQL injection?

As long as 1)you're applying this function to strings only and 2) proper encoding using mysql_set_charset() is set.
For the numbers you could simply use %d

I read somewhere that mysql_query only allows one MySQL query per call for security reason by default, is that correct?

You are right. Not much for the security but more likely by design.

If so, I don't see how any injections could be done on my code, but please let me know if there is a flaw in my logic here.

You are wrong. SQL injection stands for injecting SQL code in your query, not just single "bobby drop tables" query.

I am just wondering how safe this method of login is against attacks such as rainbow tables and brute forcing?

Rainbow tables has nothing to do here while brute-forcing still is a danger.
I don't think it's a big deal though. Not bigger than sending password in plain text.

I assume since I made the hashword and salt both very large it should be quite safe

Interesting point here.
In fact, all that hashing/salting mess is totally useless here. It's no more secure than just comparing plain passwords.

I am also wondering if this is safe from session hijacking,

there is always a possibility. If you're concerned that much, employ an SSL connection, like google mail does.

so I'm not really worried about XSS.

That's quite false feeling.
as simple as echo "Requested article: ".$_GET['id']' thing is already vulnerable.

情独悲 2024-11-07 21:43:37

看起来其他人已经把这个分开了。但我还有一个要补充的:

身份验证绕过:

<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>

当您执行 header("location: ...") 脚本仍然执行时,您仍然需要 exitdie()。事实上,通过这段代码,我知道未经身份验证的用户可以访问您的所有页面

Looks like others have picked this apart. But i have one more to add:

Authentication bypass:

<?php
session_start();
if(!$_SESSION['valid']) {header('Location: ../admin.html');}
?>

When you do a header("location: ...") The script still executes, you still have to exit or die(). So in fact by this bit of code I know that all of your pages can be accessed by an unauthenticated user.

别理我 2024-11-07 21:43:37

更多改进:

将参数引用到某些内容之前检查参数的类型。 (文本搜索除外。这需要更多一点)。缺失值可能会引发 SQL 错误,攻击者可以从中学习;)

将反 csrf 令牌放入您的登录页面,并在错误登录后进入睡眠状态,尝试防止暴力攻击。

通过https登录。通过 http,您可以通过网络推送清晰的密码。完美的中间人攻击场景(但这很难做到:)。

检查输入编码是否正确。有一些 UTF-7 攻击使用日语多字节字符,这些字符以单引号作为第二个字节。 (这可能会破坏 mysql_real_escape_string)非常棘手的东西。

使用准备好的语句

More improvements:

Check the type of your parameters before you are quoting them into something. (Except for text search. This requires a little more). A missing value could raise a SQL error where attackers can learn from ;)

Put an anti csrf token to your login page and put a sleep after a bad login try to prevent bruteforce attacks.

Login over https. Over http you push clear passwords through the net. Perfect man in the middle attack scenario (but it's quite difficult to do :).

Check for correct input encoding. There are some UTF-7 attacks which are using japanese multibyte chars which have a singlequote as second byte. (This possible breaks mysql_real_escape_string) Veeery tricky stuff.

Use prepared statements

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文