PHP文件上载 - 确保上载文件和更新数据库

时间:2012-04-04 20:18:53

标签: php file-upload xss database-security

使用PHP上传文件以确保数据库也更新的最佳做法是什么?

目前的做法

1)表单验证确认所有字段都是有效的类型,长度和清除xss攻击。

2)使用用户提交的文件名

上传到服务器的文件

3)使用用户提交的详细信息(包括文件名

)更新数据库

这是一种安全的方式吗?最好先更新数据库,然后在数据库中查询文件名,然后使用数据库检索的文件名上传文件吗?

不是寻找代码而是寻找哲学。谢谢!

2 个答案:

答案 0 :(得分:1)

表单验证是任何Web应用程序的重要组成部分,因此可以在列表中看到它。您将这里的两个最具风险的Web应用程序元素,文件上传和数据库交互结合起来,因此您显然需要谨慎行事。我猜这就是你问的原因!

我在方法方面的建议首先是不使用用户提交的文件名,这会打开你不需要的整个风险区域。除非这是您的应用程序的必需功能,否则在PHP中生成一个新的随机文件名,并使用move_uploaded_file从PHP分配的tmp_name复制到您的新随机文件名。

执行此移动后,您可以使用文件的位置更新数据库。

因此,我的方法是:

  1. 基于白名单([a-z] [A-Z] [0-9]作为建议)严格验证任何用户提供的输入。
  2. 避免将用户提供的数据回显到屏幕,如果这样做,则将编码输出到HTML实体。
  3. 避免使用用户提供的数据输入数据库或文件名,生成您控制的新文件名。
  4. 处理上传本身,并在执行一些验证检查后,根据生成的文件名将图像移动到新位置。
  5. 使用新文件名更新数据库。
  6. 我知道你不是在代码之后,但是这里有一些来自我上传的工作文件的小片段,它不是数据库部分,但是可以直接添加。

    function generate_filename() {
        // could be improved upon really
        $random_string = random_string(8);
        $filename = $random_string . time() . ".jpg";
        return $filename;    
    }
    
    
    
    if ($_FILES["file_upload"]["size"] != 0) {
        $file_name = generate_filename();
        $file_path = "/" . $upload_directory . "/" . $file_name;
        $target_file_name = SITE_ROOT . $file_path; // SITE_ROOT is a constant for the file system location. This could be /var/www/images for example.
    
        if ($_FILES["file_upload"]["type"] == "image/jpeg") {
            if (getimagesize($_FILES["file_upload"]["tmp_name"])) {
                if (move_uploaded_file($_FILES["file_upload"]["tmp_name"],$target_file_name)) {
                    exit_status("File uploaded successfully to $file_path");
                } else {
                    exit_status("Eek, something went wrong with your image upload");
                }
            } else {
                exit_status("Not a valid image");
            }
        } else {
            exit_status("Invalid file type. We only support JPEG");
        }
    } else {
        exit_status("You didn’t specify a file to upload. Try again");
    }
    

答案 1 :(得分:0)

我会用这个顺序:

第一种方法:依赖于操作顺序

  • 表单验证
  • 检查文件是否已上传(不要将其从临时文件中移出)
  • 根据您的自由选择生成新文件名
  • 使用新生成的文件名
  • 将有关文件的数据插入数据库
  • 只有这样,如果没有抛出异常,使用上面的文件名从temp移动文件。否则,文件将在请求结束时自动删除
  • 如果由于某种原因文件移动失败,您应该从数据库中删除记录。

我强烈建议使用一些PDO - 类似的库与数据库“对话”,因为它们抛出异常,而不是引发错误(如mysql_**函数)。通过这种方式,您可以确定您的查询是否成功,而无需不断检查数据库函数的结果......

第二种方法:交易

  • 表单验证
  • 检查文件是否已上传(不要将其从临时文件中移出)
  • 根据您的自由选择生成新文件名
  • 开始交易
  • 使用新生成的文件名将有关文件的数据“插入”到数据库。
  • 使用上面的文件名从temp移动文件。如果由于某种原因文件移动失败,请抛出一个execption。
  • 提交交易
  • 此时您确定已移动这两个文件并且数据已正确保留。