【问题标题】:PHP security and unique naming conventionsPHP 安全性和独特的命名约定
【发布时间】:2011-07-05 04:16:26
【问题描述】:

这样命名用户上传的图片(例如头像)有什么问题吗:

/user_id-username.jpg

例子:

/1-feont.jpg

所有图像都有唯一的名称(因为 user_id 是主键),但是安全性呢?这有什么不好的影响吗?如果有,我应该改用什么约定?

【问题讨论】:

  • 不知道您对用户名中可能的字符设置了哪些限制。但并非所有字符都可以在文件名中使用。为什么不使用 /avatar-user_id.jpg 之类的约定
  • 只要文件名包含不受用户控制的独特内容,那么应该没问题。但是,您真的希望有人上传“really_nasty_word_goes_here.jpg”并由您的机器提供给所有人吗?
  • 嗯,不错的观点。 ;) 但是让我们以画廊为例。爬虫也能找到图片,这是一个很好的访问者来源。特别是如果图像的名称像壁纸/jh8f8g_route_66.jpg。当然,我也有title属性。但是在有节制的网站中,删除一些“nasty_image_title.jpg”或使用审查器并替换一些字符串是很简单的。

标签: php security naming-conventions


【解决方案1】:

在将用户名用作文件名的一部分之前,请确保对其进行了适当的清理。用户 ID 应该是系统生成的,这样不会导致任何问题。

【讨论】:

  • 当然,文件名只包含a-z和下划线。但关键是,如果某个不受欢迎的人有记录的 id,可能会造成一些损害。也许像随机生成的字符串这样的约定更安全?
【解决方案2】:

您给图像起的名称纯粹是传统的。我不认为泄露用户名是一个安全问题。 (如果是,那么您最好立即检查您的 CMS!)但是,如果您的网站不完全安全,黑客可以利用 SQL 注入来访问您的用户数据。

但这个想法真的很牵强。您可以继续使用用户名。 :-)

IMO,只需将图像命名为 user-user_id.jpg(这里,“user”是一个普通字符串,后跟整数 - user_id)

【讨论】:

    【解决方案3】:

    一般来说没问题,但有些用户可能不喜欢显示他们的姓名,如果您的网站不完全安全,或者如果将来发现当前存在的 PHP 漏洞,则作为主键的用户 ID 可能存在漏洞未知。

    对于这类事情我倾向于使用下面的代码

    $createName = date('YmdHis');
    $fileType = '.jpg';
    $imgName = $createName.$fileType;
    

    这应该给出一个类似 20110702155513.jpg 的字符串 - 这是图像命名的完整日期和时间,并且是唯一的。

    如果您真的想要安全,那么您可以编写一个回调函数,如果由于文件名不唯一而导致失败(通常是因为在同一秒内有 2 个请求 - 不太可能但可能),那么您可以使用回退在字符串中间添加用户 ID 或使用回退作为主要命名方法,例如

    if($imgName == 'inuse'){
         $createName1 = date('Ym');
         $createName2 = date('dHis');
         $fileType = '.jpg';
         $imgName = $createName1.$userId.$createName2.$fileType;
    }
    

    这允许用户 ID 被隐藏但完全唯一。

    *Edit - * 另一种选择是使用现有格式并创建 MD5 哈希,代码类似于

    $user_id = 'user_id';
    $username = 'username';
    $fileType = '.jpg';
    $fileName = md5($user_id).'-'.md5($username).$fileType;
    

    希望对你有帮助

    【讨论】:

    • 是的,没关系。我知道那个方法。但是真正的黑客有一些身份可以做什么呢?我想...不多,当网站工具无法创建自己的文件名时。
    • @Mr Sooul 这取决于您如何开发您的网站,一根绳子有多长?例如。如果您使用 JavaScript 进行表单验证并且不使用 PHP 进行验证,那么我可以绕过 JS,使用带有一些智能 cURL 的主键将信息发布到您的数据库,这通常是您不允许的。正如我所说,这通常不是一个大问题,但我仍然更喜欢使用完全隐藏 ID 或根本不使用它的方法。我无法评论尚未发现或创建的问题或您的特定站点上可能发生的问题:-)
    • @Mr Sooul 另一个问题可能是,如果用于登录的 cookie 或会话 ID 使用密钥,那么我可能会使用该密钥来伪造会话并获得对用户帐户的完全控制,包括更改密码。 1 选项是采用上面的用户 ID 和名称选项,并从中创建一个 MD5 散列用于命名,现在将编辑我的答案以包含该选项的代码
    • 没错,但我们可以使用盐,然后哈希会话 id ;) 但总而言之,我将更新我的头像列表。现在……画廊呢? photo_id 并不像潜在的 user_id 那样有用......那么,在您看来,我可以有意识地、安全地使用 photo_id 来提供唯一的命名吗?
    • 我没有看到任何真正的问题,我对画廊的风险通常较低,所以我会允许更多地披露他们但是,我仍然使用任何 ID 为任何表单建立一个隐藏字段站点,该字段从服务器动态地获得一个值,如果它在发布时不匹配,则脚本失败。编写起来可能很棘手,但我通常会在 SESSION 中使用现有的数值变量并使用算法对其进行操作,以便接收脚本可以评估密钥是否正确,这实际上只是避免了机器人操作
    【解决方案4】:
    • 当您有用户同时上传时,使用 Ryan 建议的 日期 会失败
    • 当用户可以更改其用户名时,使用 用户名 会失败。 “失败”在这里有点困难,但您必须移动文件,这是使用其他解决方案时不需要的东西
    • 如果 ID 是数据库中自动生成的自动增量 ID,则使用 id 可以解决所有并发问题。与 Kerrek SB 相反,我认为这不会在唯一标识符和文件系统上的图像之间建立联系。我的意思是它是独一无二的,你可以使用它。

    如果您经常公开使用该 ID,则使用该 ID 还可以让您的用户轻松找到/链接他们的图片。另一方面,如果您在 URL 中只有用户名 - 例如/profile/$username,那么我也会在图像文件名中使用用户名 - 保持一致。

    关于安全性:如果您清理用户名,一切都很好。只要确保它是唯一的,这样人们就不能覆盖彼此的名字(这意味着您需要对数据库中的用户名使用与图像文件名中的用户名相同的卫生规则)。

    如果您需要手动查找图像,使用用户名作为图像名称也可以“更容易”找到图像,但这种情况发生的频率可能不足以对您有价值。

    总而言之,我会使用 ID。

    【讨论】:

    • 感谢您的好评。头像只是例子。总而言之,我宁愿为头像生成随机字符串。但是当我需要漂亮的标题时(例如在画廊中),我宁愿使用 photo_id 和经过清理的标题。对于不速之客来说,我只是对 user_id 的价值感到好奇。
    【解决方案5】:

    像您在第一个示例中使用的方式命名文件没有巨大风险,但为了使其更安全,您为什么不使用更好的东西,例如

        function Naming($username,$imagename)
    {
        $uniq = time() ;
        $name  = $uniq.'-'.$username.'-'.$imagename ;
        return $name ;
    }
    

    我认为最好避免使用用户 ID

    【讨论】:

      【解决方案6】:

      唯一的 user_id 就足够了,你不需要“用户名”。
      问题不在这里,而在于文件数(在一个文件夹中)。
      在文件夹中将它们除以 1000(或除以 100):将 ID 字符串的第一个、第二个和第三个符号放入单独的目录中:

      ID = 10524.jpg  
      filename = 1/0/5/10524.jpg
      

      如果算法很难写,可以试试这个功能:

      function getStorePath($filename, $base_dir)
      {
          //file should have extension
          $ext_pos = strrpos($filename, '.');
          if ($ext_pos===false) return false;
      
          //extension will be sanitized (filtered actually)    
          $ext = preg_replace("|\W+|", "", substr($filename, $ext_pos+1));
          if (empty($ext)) return false;
          if (in_array($ext, array('php', 'shtml', 'cgi', 'inc', 'module', 'sh', 'sql', 'class'))) return false;
      
          //filename will be filtered    
          $filename = preg_replace("|\W+|", "", substr($filename, 0, $ext_pos));
      
          if (empty($filename)) $filename = mt_rand(100000, 999999).round(microtime(true)*1000000);
      
          //let's create path to the file.
          //we will take first 3 symbols of filename as names of folders    
          $d = realpath($base_dir).'/';
      
          //first symbol
          $d .= $filename[0].'/';
          if (!file_exists($d))
          {
              $md = mkdir($d, 0755);
              if ($md===false && !file_exists($d)) return false;
          }
      
          //second symbol
          if (isset($filename[1]))
          {
              $d .= $filename[1].'/';
              if (!file_exists($d))
              {
                  $md = mkdir($d, 0755);
                  if ($md===false && !file_exists($d)) return false;
              }
          }
      
          //and third symbol
          if (isset($filename[2]))
          {
              $d .= $filename[2].'/';
              if (!file_exists($d))
              {
                  $md = mkdir($d, 0755);
                  if ($md===false && !file_exists($d)) return false;
              }
          }
      
          if (!file_exists($d.$filename.'.'.$ext)) return $d.$filename.'.'.$ext;
          else return false;
      }
      

      【讨论】:

        【解决方案7】:

        我通常将我的图像命名为随机字符串,然后将其存储在附加到上传者 ID 的数据库中。您还可以通过这种方式存储有关图像的其他数据。

        $filename = uniqid('', true) 。 '.jpg';

        图像表

        标识 |用户 ID |文件名 |等等

        【讨论】:

        • 这样,如果您决定为每个用户存储多个图像,则无需更改所有内容。
        【解决方案8】:

        只有我自己的两分钱。 如果您要添加更多头像供用户选择,最好使用 uniqid() 之类的函数而不是 user of。否则,您可以随心所欲。

        不过,我使用用户 ID 和 time() 的 MD5 哈希。只是偏好问题。

        【讨论】:

          猜你喜欢
          • 2016-12-16
          • 1970-01-01
          • 2012-12-03
          • 1970-01-01
          • 2016-03-25
          • 2018-03-21
          • 1970-01-01
          • 2015-11-21
          • 1970-01-01
          相关资源
          最近更新 更多