2017-01-13 1 views
1

私はPythonで単純なファイルサーバーを書いています。ファイル名はクライアントによって提供され、信頼されていないとみなすべきです。現在のディレクトリ(そのディレクトリ内またはそのサブディレクトリ内)内のファイルに対応することを確認するにはどうすればよいですか?次のようになりますか:Python3で現在のディレクトリにファイルを開くだけを許可する方法は?

pwd=os.getcwd() 
if os.path.commonpath((pwd,os.path.abspath(filename))) == pwd: 
    open(filename,'rb') 

とすればよいですか?

import os, os.path 

def in_cwd(fname): 
    path = os.path.dirname(os.path.realpath(fname)) 
    return path.startswith(os.getcwd()) 

カノニカル経路にfnameを変換し(標準形式で)カレントディレクトリがその接頭辞である場合

+0

何についてhttps://docs.python.org/3/library/pathlib.html#pathlib.Path.resolve? –

答えて

2

os.path.realpathを使用して正規のパスにファイル名を変換し、ディレクトリの部分を取得し、参照../を含むシンボリックリンクとパスを処理します。


更新

残念ながら、上記のコードは少し問題があります。例えば、

'/a/b/cd'.startswith('/a/b/c') 

戻りTrueが、我々は間違いなくは、ここでその振る舞いをしたくありません!幸い、簡単な修正があります:プレフィックステストを実行する前に、パスにos.sepを追加するだけです。新しいバージョンでは、OSパス名の大文字と小文字の区別がない問題もos.path.normcaseで処理します。

import os, os.path 

def clean_dirname(dname): 
    dname = os.path.normcase(dname) 
    return os.path.join(dname, '') 

def in_cwd(fname): 
    cwd = clean_dirname(os.getcwd()) 
    path = os.path.dirname(os.path.realpath(fname)) 
    path = clean_dirname(path) 
    return path.startswith(cwd) 

前のコードの欠陥を指摘してくれたDSMに感謝します。


これはもう少し効率的なバージョンです。これはos.sepを追加し、文字列接頭辞テストを実行するよりも頑強であるos.path.commonpathを使用します。

def in_cwd(fname): 
    cwd = os.path.normcase(os.getcwd()) 
    path = os.path.normcase(os.path.dirname(os.path.realpath(fname))) 
    return os.path.commonpath((path, cwd)) == cwd 
+0

これはかなり良い解決策です。私はテストケースでそれを実行しようとしましたが、存在しないファイルの場合は失敗するようです(例えば 'foo.py')。それはfalseの代わりにtrueを返します。編集:それは問題ではないかもしれません。 OPは存在しないファイルを受け取ったときに 'open'が潜在的に受信して(例外をスローする)うれしく思います。だから+1。 – Tagc

+0

@Tagc私は自分の答えを更新したので、以前のコメントも更新する必要があります。 :) 'in_cwd'が' True'を返す場合は、ファイルを提供したい場合にファイルが実際に存在するかどうかをテストできます。実際には、 'in_cwd'がまだ存在しないファイルに対して有効なパスに' True'を返すという利点があります。それを使って、cwdに保存されているファイルの提案されたパスを検証することができます。 –

関連する問題