PHP:base64_encode 是不是可以防止 mysql 注入?

Posted

技术标签:

【中文标题】PHP:base64_encode 是不是可以防止 mysql 注入?【英文标题】:PHP: Does base64_encode protect from mysql injections?PHP:base64_encode 是否可以防止 mysql 注入? 【发布时间】:2013-08-01 10:19:41 【问题描述】:

我正在尝试设置一个 php 页面,该页面将安全地接受文件上传(简历),将其存储为 mysql blob,并稍后提供下载。但是当我稍后下载 PDF 进行查看时,它们似乎总是损坏并且无法正常打开。

感谢 Jgoettsch (php: reversing mysql_real_escape_string's effects on binary) 提出的问题,我意识到通过 mysql_real_escape_string 提供文件数据(以防止注入)可能会损坏文件内容,因此想到通过 base64_encode() 传递二进制文件,并且下载前使用 base64_decode()。

这里有一些样机代码展示了我目前在做什么(这是行不通的):

上传:

<? 
// Get file contents
$cv_pointer = fopen($_FILES['cv']['tmp_name'], 'r');
$cv_content = fread($cv_pointer, filesize($_FILES['cv']['tmp_name']));
fclose($cv_pointer);

// Insert SQL
$sql = sprintf("INSERT INTO documents (name, file, size, date_uploaded)
  VALUES ('%s', '%s', '%s', NOW())",
    mysql_real_escape_string($_FILES['cv']['name']),
    mysql_real_escape_string($cv_content),
    mysql_real_escape_string($_FILES['cv']['size']));
$result = mysql_query($sql);
?>

还有下载:

<? 
if (isset($_GET['view_cv'])) 
  $cv = mysql_fetch_assoc($rsApplicationCv);

  header("Content-length: ".$cv['size']); 
  header("Content-type: application/pdf"); 
  header("Content-disposition: attachment; filename=".$cv['name']);
  echo $cv['file'];
  exit();

?>

这是我的问题:

    如果您有文件上传字段,该字段是否容易受到 sql 注入?还是我不必要地担心?显然,如果我可以直接将二进制文件传递到 blob 字段而不进行任何翻译,这个文件上传任务会简单得多。 如果我通过 base64_encode() 提供上传的文件内容,那是否等同于清理?还是我应该对其进行编码,然后另外通过 mysql_real_escape_string 传递编码的字符串? 这一切似乎只是为了存储和获取 PDF 需要付出很多努力。对于这种常见需求,是否有更简单的解决方案,但我还没有发现?

提前致谢!

【问题讨论】:

使用 mysqli 或 PDO 与准备好的查询和占位符,应该可以解决编码和注入问题。 注射是安全的,就像不将叉子塞进电源插座可以防止触电一样。注入漏洞规则:如果您在查询中使用“外部”数据,那么您很容易受到攻击。数据来自哪里并不重要,即使它来自您自己。您仍然可以轻松地注入自己的查询。 @MR.外星人:想更具体地说明你不想做什么? 在数据库中存储任意二进制数据通常被认为是一个坏主意。您应该存储的是对磁盘上文件或 Amazon S3 等大容量对象存储服务的引用。另外请不要在新代码中使用mysql_query,它已被弃用,并已从 PHP 的未来版本中删除。如果操作正确,转义二进制数据不会损坏它。 @TopherHunt 这不是转义数据的最佳方式,但如果您仍在使用破旧的mysql_query 界面,这是唯一可靠的方式。转义只是为了让 MySQL 正确解释您的数据,并且在检索时它应该没问题。但是,如果您不小心双重转义了您的数据,这可能会造成一团糟。我真的强烈建议不要将任意二进制文件放入数据库。他们不属于那里。 【参考方案1】:

既然你在谈论消毒,我假设这是一个公共网站,陌生人将上传文件。存储用户提交的 PDF 文件是一个非常糟糕的想法。首先,您如何确定您收到的文件甚至是 PDF?用户 100% 有可能将恶意文件卷曲到您的数据库中,并让用户在不知不觉中下载病毒。 PDF 本身(如果我没记错的话)实际上可以在某些 Windows 操作系统中执行病毒,就像 WMV 和 WMA 文件一样。

如果您绝对需要 PDF,那么最好的选择是创建您自己的 PDF 文件,其中包含用户提交的经过净化的数据。您可能可以在网上找到有关如何执行此操作的教程。我个人不建议首先使用 PDF,因为您可以使用 html 和 CSS 来构建简历并完美地打印出来。

【讨论】:

谢谢安德鲁。 PDF 将由公众提交,短期内我看不到解决办法。我们需要让准实习生轻松申请职位,并以最标准的形式接受他们的简历(.docx、.doc、.pdf)。 HR 不会要求申请人将他们的简历复制并粘贴到 CKeditor 或类似的东西中。 是的,我知道您想要构建一个对用户友好的网络应用程序,但是在处理文件时,它变得相当困难。除了让自己受到安全漏洞的影响之外,我没有看到任何短期解决方案。一般来说,您不必担心来自 MYSQLi 或 PDO 的注入,但真正的问题是下载文件的用户。 PDF 文件一般不容易受到攻击。我不知道最新的 Adob​​e Reader 更新未修复任何漏洞。确实值得检查该文件实际上 一个真正的 PDF,但没有必要完全放弃 PDF 上传。 谢谢大家。我把这一切都铭记在心。听起来mysqli是我需要进入的方向,我正朝着那个方向前进。【参考方案2】:

Q如果你有一个文件上传字段,那个字段是否容易被sql注入?

A 是的(有点。易受 SQL 注入攻击的不是表单上的字段;该漏洞实际上存在于处理请求中提交的值的代码中。)

还是我不必要地担心?

A不。您应该始终意识到可能发生的坏事,并以防止漏洞暴露(和利用)的方式编写代码。

Q如果我通过 base64_encode() 提供上传的文件内容,那是否等于净化?

A 差不多了,只要您的 base64_encode 保证返回值将仅包含 [A-Za-z0-9+./=]。最佳做法是使用绑定参数

Q 还是我应该对其进行编码,然后再通过 mysql_real_escape_string 传递编码的字符串?

A 除非使用带有绑定参数的预准备语句,否则最佳实践规定所有值(包括 base64_encoded 值)都通过 mysql_real_escape_string 运行,如果它们包含在要提交给数据库。

【讨论】:

以上是关于PHP:base64_encode 是不是可以防止 mysql 注入?的主要内容,如果未能解决你的问题,请参考以下文章

C 语言实现 php base64_encode

PHP base64_encode 在URL地址参数编码上使用

base64_encode 字符串的 php 大小 - 文件

如何在 PHP 中解析 base64_encode() 的 Json 结果

php base64_encode 如何在java中decode

php解密 base64