2015-01-27 15 views
9

Mam wiele FileFields w mojej aplikacji django, które mogą należeć do różnych użytkowników. Szukam dobry sposób ograniczenia dostępu do plików dla użytkownika, który nie jest właścicielem pliku.Ograniczanie dostępu do prywatnych plików do pobrania w Django

Jaki jest najlepszy sposób, aby to osiągnąć? Jakieś pomysły?

+0

proponuję podążać [Jak zrobić plik prywatny poprzez zapewnienie url że tylko uwierzytelnionym użytkownikom Zobacz] (http: //stackoverflow.com/questions/28007770/), ale musisz zaimplementować własną metodę, aby ograniczyć dostęp innych użytkowników do ...! –

Odpowiedz

7

Niestety rozwiązanie @ Mikko nie może faktycznie działać w środowisku produkcyjnym, ponieważ django nie jest przeznaczony do wyświetlania plików. W środowisku produkcyjnym pliki muszą być obsługiwane przez twój serwer HTTP (np. Apache, Nginx itp.) I nie przez twój serwer aplikacji/django (np. Uwsgi, gunicorn, mod_wsgi itp.).

Dlatego ograniczenie dostępu do pliku jest niezbyt łatwe: Potrzebujesz sposobu, aby serwer HTTP zapytał serwer aplikacji, czy można przesłać plik do konkretnego użytkownika, który go żąda. Jak możesz zrozumieć, to wymaga modyfikacji zarówno twojej aplikacji http: //www.http://www.google.com/go/img/default.aspx.

Najlepszym rozwiązaniem powyższego problemu jest django-sendfile (https://github.com/johnsensible/django-sendfile), który wykorzystuje mechanizm X-SendFile do implementacji powyższego. Kopiuję z opisu projektu:

To jest wrapper dotyczący specyficznych dla serwera WWW metod przesyłania plików do klientów WWW. Jest to przydatne, gdy Django musi sprawdzać powiązane pliki uprawnień, ale nie chce podawać rzeczywistych bajtów samego pliku. to znaczy, że serwowanie dużych plików nie jest tym, za co jest przeznaczony Django.

Aby lepiej zrozumieć mechanizm senfile, proszę przeczytać tę odpowiedź: Django - Understanding X-Sendfile

1

Zazwyczaj nie kierują Państwo prywatnych plików przez zwykłe pliki statyczne bezpośrednio przez Apache, Nginx lub jakikolwiek serwer internetowy, z którego korzystamy. Zamiast tego napisz niestandardowy widok Django, który obsługuje sprawdzanie uprawnień, a następnie zwraca plik jako pobieranie strumieniowe.

  • Upewnij się, że pliki są w specjalnym folderze folder prywatny i nie narażone przez Django MEDIA_URL lub STATIC_URL

  • Napisz widok, który będzie

    • Sprawdź, czy użytkownik ma dostęp do plik w logice widoku

    • Otwórz plik z Python's open()

    • Powrót odpowiedzi HTTP, który dostaje przetwarzał zbiór jako parametru http.HttpResponse(_file, content_type="text/plain")

przykładowo patrz download()here.

2

Jeśli potrzebujesz tylko umiarkowany bezpieczeństwa, moje podejście byłoby następujące:

1) Gdy użytkownik przesyła plik , wygeneruj dla niej trudną do odgadnięcia ścieżkę. Na przykład możesz utworzyć folder z losowo wygenerowaną nazwą dla każdego przesłanego pliku w folderze/static. Można to zrobić bardzo prosto za pomocą tego przykładowego kodu:

file_path = "/static/" + os.urandom(32).encode('hex') + "/" + file_name 

W ten sposób będzie to bardzo trudne do odgadnięcia, gdzie przechowywane są pliki inni.

2) W bazie danych połącz właściciela z plikiem. Przykładowy schemat może być:

uploads(id, user_id, file_path)

3) Użyj właściwość dla swoich FileFields w modelu, aby ograniczyć dostęp do pliku, w ten sposób:

class YourModel(models.Model) 
    _secret_file = models.FileField() 

    def get_secret_file(self): 
     # check in db if the user owns the file 
     if True: 
      return self._secret_file 
     elif: 
      return None # or something meaningful depanding on your app 

    secret_file = property(get_secret_file) 
+0

dziękuję bardzo bardzo pomocne – soField

0

to najlepiej obsługiwane przez serwer, np nginx secure link module (nginx musi być sporządzona z --with-http_secure_link_module)

przykład z dokumentów:

location /some-url/ { 
    secure_link $arg_md5,$arg_expires; 
    secure_link_md5 "$secure_link_expires$uri$remote_addr some-secret"; 

    if ($secure_link = "") { 
     return 403; 
    } 

    if ($secure_link = "0") { 
     return 410; 
    } 

    if ($secure_link = "1") { 
     // authorised... 
    } 
} 

plik będzie dostępne, takie jak:

/some-url/some-file?md5=_e4Nc3iduzkWRm01TBBNYw&expires=2147483647 

(Byłoby zarówno czas ograniczony i związany do użytkownika pod tym adresem IP).

Generowanie tokenu przekazać użytkownikowi użyłby coś takiego:

echo -n 'timestamp/some-url/some-file127.0.0.1 some-secret' | \ 
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = 
Powiązane problemy