【发布时间】: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 正确解释您的数据,并且在检索时它应该没问题。但是,如果您不小心双重转义了您的数据,这可能会造成一团糟。我真的强烈建议不要将任意二进制文件放入数据库。他们不属于那里。
标签: php mysql blob sanitization