3

次のように定義されたモデルの一部があります。

logo_image = models.ImageField(upload_to=lambda i, fn: "logo_%s"%(fn), height_field="logo_image_height", width_field="logo_image_width")

upload_to 関数について質問がありました。

django の FileField.upload_to のドキュメントによると、2 番目のパラメーターfilenameは「ファイルに最初に指定されたファイル名」です。

現在、HTTP、ファイルのアップロードなどについて知っているので、エンド ユーザーのクライアントはファイル名を簡単に偽造できます。具体的には、たとえば、エンド クライアントが「/etc/passwd」というファイルをアップロードできなかった場合、単純なコード ( lambda i, fn: "logo_%s"%(fn)) を使用すると、結果のファイルが にアップロードされ/etc/passwdませんか? filenameパラメータをエスケープする必要がありますか?

#using django's example of using full paths in settings module,
#MEDIA_ROOT="/tmp/media"
>>> os.path.join("/tmp/media/", "apple.jpg")
'/tmp/media/apple.jpg'
>>> os.path.join("/tmp/media/", "/etc/passwd")
'/etc/passwd'

提案/回答/説明をありがとう。

編集

注目すべき重要なメソッドは、files.py の 272 行目付近にあります

272         def get_directory_name(self):
273             return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
274     
275         def get_filename(self, filename):
276             return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
277     
278         def generate_filename(self, instance, filename):
279             return os.path.join(self.get_directory_name(), self.get_filename(filename))

カスタムを定義すると、次のように()upload_toが置き換えられますgenerate_filename

226             if callable(upload_to):
227                 self.generate_filename = upload_to

次に、save() メソッドで:

89      def save(self, name, content, save=True):
90          name = self.field.generate_filename(self.instance, name)
91          self.name = self.storage.save(name, content)

そして、返されたファイル名はストレージ クラスに渡され、最終的に _os.py util モジュールsafe_joinで django 置換関数が呼び出されます。

その機能は私の恐怖を軽減するようです:

24    def safe_join(base, *paths):
25      """
26      Joins one or more path components to the base path component intelligently.
27      Returns a normalized, absolute version of the final path.
28  
29      The final path must be located inside of the base path component (otherwise
30      a ValueError is raised).
31      """
4

1 に答える 1

1

あなた自身の質問に答えたと思います。os.path.join() が機能する方法を明確にするための 1 つのポイントは、(os.path に関連する Python ドキュメントによると) 破棄される前のディレクトリを削除することです。したがって、os.path.join() の呼び出しで観察した動作は、説明されている方法と一致しています。

注意すべきもう 1 つの点: get_filename() 関数は os.path.basename() を呼び出します。これは、ディレクトリ パスを取り除き、ベース名のみを返します。したがって、upload_to= パラメータがなければ、この可能性の危険はありません。

ただし、独自の upload_to 関数で ImageField() をオーバーライドすると、この関数は呼び出されず、os.path.basename() を呼び出した方がよい場合があります。まず、ファイル名を完全なディレクトリ パスとして保存することも避けます。したがって、upload_to 関数内で os.path.basename() も呼び出すことが望ましいことがわかりました。他の誰かがこの問題に遭遇しましたか?

詳細については、http: //hustoknow.blogspot.com/2010/08/try-me-out.htmlを参照してください。

于 2010-08-30T20:34:49.027 に答える