38 votes

Stocker les fichiers PHP (/ PHP-FPM / Apache) de téléchargement temporaire dans la RAM plutôt que dans le système de fichiers (ou uniquement crypté)?

Question d'origine

Si le projet sur lequel je travaille est mort paranoïaque à propos de l'upload de fichiers.
Dans le champ d'application de cette question, je n'utilise pas ce terme en ce qui concerne les charges utiles; je parle de la confidentialité.

Les programmes peuvent toujours planter et laisser les fichiers temporaires de flâner autour du système de fichiers. C'est normal. Le légèrement la confidentialité de paranoïa peut écrire un cronjob qui frappe le dossier de fichiers temporaires toutes les quelques minutes et supprime rien de plus que quelques secondes avant que la tâche cron appel (pas tout, tout simplement parce que sinon, il pourrait attraper un fichier en cours d'upload).

...malheureusement, nous profitons de cette parano un peu plus loin:

Idéalement, on aimerait ne jamais voir les fichiers temporaires de téléchargement de fichiers n'importe où, mais dans les processus liés à la RAM.

Est-il un moyen d'enseigner PHP pour rechercher fichier temporaire sous forme de gouttes dans la mémoire plutôt que dans le système de fichiers? Nous utilisons PHP-FPM en CGI et Apache en tant que notre serveur, dans le cas qui rend tout plus facile. (Remarque aussi: 'Filesystem' est le mot clé ici, plutôt que de "disque", car il y a bien sûr des moyens de cartographier le système de fichiers RAM, mais cela ne résout pas le problème de l'accessibilité et automatique de post-crash-nettoyage de problème).

Sinon, est-il possible que ces fichiers temporaires peuvent être chiffrés immédiatement lorsqu'elles sont écrites sur le disque, de sorte qu'ils ne sont jamais tenues dans le système de fichiers sans chiffrement?


Thread de présentation

Je ne peux malheureusement seulement accepter une réponse mais à tous ceux qui lisent ceci, tout le fil est extrêmement précieux et contient le collectif idées de beaucoup de gens. En fonction de ce que vous espérez atteindre, l'on a accepté la réponse peut ne pas être intéressant pour vous. Si vous êtes venu ici par le biais d'un moteur de recherche, veuillez prendre un moment pour lire le thread entier.

Voici une compilation de usecases que je les vois pour la référence rapide:

Re: PHP les fichiers temporaires

  • La RAM au lieu de disque (par exemple, en raison de I/O préoccupations) → RAMdisk/comparables (plasmid87, Joe Hopfgartner)

  • Immédiate (par système de fichiers de l'utilisateur) chiffrement → encFS (ADW) (+ une chasse aux sorcières comme par Sander Marechal)

  • Sécuriser les autorisations de fichier → restrictive natif de Linux autorisations (éventuellement par vhost) (Gilles) ou SELinux (voir les différents commentaires)

  • Processus mémoire associée, au lieu de système de fichiers (donc un processus de collision supprime les fichiers) (à l'origine prévu par la question)

Re: vos fichiers, post-télécharger

5voto

Cal Points 5474

Avez-vous envisagé de mettre une couche entre l'utilisateur et le serveur web? En utilisant quelque chose comme perlbal avec certains de code personnalisé à l'avant du serveur web vous permettent d'intercepter les fichiers téléchargés avant qu'elles ne sont écrites nulle part, les chiffrer, les écrire dans un local ramdisk et puis procuration à cette requête, le serveur web de bonne qualité (avec le nom de fichier et la clé de déchiffrement pour les fichiers).

Si le PHP, le processus se bloque, le fichier crypté est à gauche, mais ne peut pas être déchiffré. Pas de données non chiffrées qui est écrit à vive (ram)disque.

4voto

Phil Lello Points 4582

CGI à la rescousse!

Si vous créez un répertoire cgi-bin, et de configurer correctement, vous obtiendrez le message via stdin (autant que je puisse en dire, les fichiers ne sont pas écrites sur le disque à tous de cette façon).

Donc, dans votre configuration apache ajouter

ScriptAlias /cgi-bin/ /var/www/<site-dir>/cgi-bin/
<Directory "/var/www/<site-dir>/cgi-bin">
    AllowOverride None
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
    Order allow,deny
    Allow from all
</Directory>

Ensuite, écrire un script CGI en mode script PHP pour parser les données post. De mon (limitée) de test, pas de fichiers locaux semblent être créé. L'exemple de vidages de ce qu'il lit sur l'entrée standard ainsi que les variables d'environnement, pour vous donner une idée de ce qu'il y a à travailler avec.

Exemple de script installé dans /var/www/cgi-bin/test

#!/usr/bin/php
Content-type: text/html

<html><body>
<form enctype="multipart/form-data" action="/cgi-bin/test" method="POST">
    <!-- MAX_FILE_SIZE must precede the file input field -->
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    <!-- Name of input element determines name in $_FILES array -->
    Send this file: <input name="userfile" type="file" />
      <input type="submit" value="Send File" />
</form>
<pre>
<?
echo "\nRequest body\n\n";
$handle = fopen ("php://stdin","r");
while (($line = fgets($handle))) echo "$line";
fclose($handle);
echo "\n\n";
phpinfo(INFO_ENVIRONMENT);
echo "\n\n";
?>
</pre>
</body></html>

Exemple de sortie C'est la sortie (source) quand je télécharge un fichier de texte brut:

<html><body>
<form enctype="multipart/form-data" action="/cgi-bin/test" method="POST">
    <!-- MAX_FILE_SIZE must precede the file input field -->
        <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
        <!-- Name of input element determines name in $_FILES array -->
        Send this file: <input name="userfile" type="file" />
          <input type="submit" value="Send File" />
</form>
<pre>

Request body

-----------------------------19908123511077915841334811274
Content-Disposition: form-data; name="MAX_FILE_SIZE"

30000
-----------------------------19908123511077915841334811274
Content-Disposition: form-data; name="userfile"; filename="uploadtest.txt"
Content-Type: text/plain

This is some sample text

-----------------------------19908123511077915841334811274--


phpinfo()

Environment

Variable => Value
HTTP_HOST => dev.squello.com
HTTP_USER_AGENT => Mozilla/5.0 (X11; U; Linux x86_64; en-GB; rv:1.9.2.16) Gecko/20110323 Ubuntu/10.04 (lucid) Firefox/3.6.16
HTTP_ACCEPT => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTP_ACCEPT_LANGUAGE => en-gb,en;q=0.5
HTTP_ACCEPT_ENCODING => gzip,deflate
HTTP_ACCEPT_CHARSET => ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP_KEEP_ALIVE => 115
HTTP_CONNECTION => keep-alive
HTTP_REFERER => http://dev.squello.com/cgi-bin/test
CONTENT_TYPE => multipart/form-data; boundary=---------------------------19908123511077915841334811274
CONTENT_LENGTH => 376
PATH => /usr/local/bin:/usr/bin:/bin
SERVER_SIGNATURE => <address>Apache/2.2.14 (Ubuntu) Server at dev.squello.com Port 80</address>

SERVER_SOFTWARE => Apache/2.2.14 (Ubuntu)
SERVER_NAME => dev.squello.com
SERVER_ADDR => 127.0.0.1
SERVER_PORT => 80
REMOTE_ADDR => 127.0.0.1
DOCUMENT_ROOT => /var/www/dev.squello.com/www
SERVER_ADMIN => webmaster@localhost
SCRIPT_FILENAME => /var/www/dev.squello.com/cgi-bin/test
REMOTE_PORT => 58012
GATEWAY_INTERFACE => CGI/1.1
SERVER_PROTOCOL => HTTP/1.1
REQUEST_METHOD => POST
QUERY_STRING =>  
REQUEST_URI => /cgi-bin/test
SCRIPT_NAME => /cgi-bin/test


</pre>
</body></html>

4voto

Phil Lello Points 4582

J'ai eu un flash d'inspiration sur ce: trou noir des systèmes de fichiers.

Essentiellement, c'est un faux système de fichiers, où les données n'est jamais écrit, mais tous les fichiers n'existe, et n'ont pas de contenu.

Il y a une discussion sur unix.se sujet, et la réponse implique un FUSIBLE de mise en œuvre de tout cela (cité ici):

Ce n'est pas pris en charge hors de la boîte tout unix, je sais, mais vous pouvez le faire assez beaucoup de n'importe quoi avec Le FUSIBLE. Il y a au moins une mise en œuvre de nullfs1, un système de fichiers où chaque fichier existe et se comporte comme /dev/null(ce n'est pas la seule application que j'ai jamais vu).

1 ne Pas confondre avec le *BSD nullfs, qui est analogue à bindfs.

Je n'ai pas eu la chance de tester cela , mais si vous définissez la upload_tmp_dir pour un trou noir de l'emplacement, de la télécharger (va|devrait jamais être écrite sur le disque, mais reste disponible dans $HTTP_RAW_POST_DATA (ou php://input). Si ça fonctionne, c'est mieux de le corriger PHP

3voto

Gilles Points 37537

Je ne suis pas familier avec PHP, donc ma réponse ne sera pas directement la carte dans un, mais je pense que vous avez travaillé par des idées fausses sur ce que la protection de diverses caractéristiques du système de fournir, qui vous ont conduit à rejeter des solutions valables en faveur de solutions qui ont exactement les mêmes propriétés de sécurité. À partir de vos commentaires, je comprends que vous êtes sous Linux, la plupart de ma réponse s'applique à d'autres systèmes unix, mais pas à d'autres systèmes tels que Windows.

Aussi loin que je peux voir, vous êtes préoccupé par les trois scénarios d'attaque:

  1. L'attaquant de l'accès physique à la machine, il s'arrête, sort le disque et lire son contenu à son loisir. (Si l'attaquant peut lire votre mémoire, vous avez déjà perdu.)
  2. L'attaquant peut exécuter du code en tant qu'utilisateur sur la machine.
  3. Un bug dans les scripts CGI permet à un processus de lire les fichiers temporaires créés par d'autres processus.

Le premier type d'attaquant peut lire tout ce qui est en clair sur le disque, et rien de ce qui est chiffré avec une clé qu'elle n'a pas.

Ce que le deuxième type d'attaquant peut faire dépend de savoir si elle peut exécuter du code sous le même utilisateur que de l'exécution de vos scripts CGI.

Si elle ne peut exécuter du code que d'autres utilisateurs, alors l'outil pour protéger les fichiers est des autorisations. Vous devriez avoir un répertoire qui est le mode de 700 (= drwx------), c'est à dire accessible uniquement par un utilisateur, et il appartient à l'utilisateur qui exécute les scripts CGI. Les autres utilisateurs ne seront pas en mesure d'accéder aux fichiers dans ce répertoire. Vous n'avez pas besoin de chiffrement ou d'autres mesures de protection.

Si elle peut exécuter du code comme le CGI de l'utilisateur (ce qui inclut, évidemment, d'exécuter du code en tant que root), alors vous avez déjà perdu. Vous pouvez voir la mémoire d'un autre processus, si vous êtes en cours d'exécution de code que l'utilisateur - débogueurs de le faire tout le temps! Sous Linux, vous pouvez facilement voir par vous-même en explorant /proc/$pid/mem. Par rapport à la lecture d'un fichier, la lecture de la mémoire d'un processus est un peu plus difficile sur le plan technique, mais de la sécurité, il n'y a pas de différence.

Donc avoir les données dans des fichiers n'est pas en soi un problème de sécurité.

Nous allons maintenant examiner la troisième préoccupation. Le souci, c'est qu'un bug dans le CGI permet à l'attaquant de snoop sur les fichiers mais pas d'exécuter du code arbitraire. Est-ce lié à un problème de fiabilité − si le processus CGI meurt, elle peut laisser des fichiers temporaires derrière. Mais c'est plus général: le fichier peut être lu par un concurremment-exécution de script.

Le meilleur moyen de se protéger contre ce n'est en effet pour éviter d'avoir les données stockées dans un fichier. Cela devrait être fait au niveau de PHP ou de bibliothèques, et je ne peux pas vous aider. Si il n'est pas possible, alors nullfs comme suggéré par Phil Lello est raisonnable de solution de contournement: le processus PHP va penser que c'est l'écriture de données dans un fichier, mais le fichier ne contient aucune donnée.

Il y a une autre common unix truc qui pourrait être utile ici: une fois que vous avez créé un fichier, vous pouvez dissocier (supprimer) et continuer à travailler avec elle. Dès qu'il est déconnecté, le fichier ne peut pas être accédé par son ancien nom, mais le reste des données dans le système de fichiers, tant que le fichier est ouvert dans au moins un processus. Cependant, c'est surtout utile pour la fiabilité, pour obtenir le système d'exploitation pour supprimer les données lorsque le processus meurt pour une raison quelconque. Un attaquant qui peut ouvrir des fichiers arbitraires avec les processus d'autorisations d'accès aux données par le biais /proc/$pid/fd/$fd. Et un attaquant qui peut ouvrir des fichiers à tout moment, a une petite fenêtre entre la création du fichier et son dissociation: si elle peut ouvrir le fichier puis, elle peut regarder les données qui sont ajoutés par la suite. Cela peut néanmoins être utile de protection, il se trouve que l'attaque en un qui est sensible au temps et peut nécessiter de nombreuses connexions simultanées, donc pourrait contré ou au moins rendue beaucoup plus difficile par un limiteur de vitesse de connexion.

1voto

ADW Points 3018

Avez-vous envisagé d'utiliser FUSE pour créer un répertoire crypté accessible uniquement à un utilisateur spécifique?

http://www.arg0.net/encfs

La mémoire ne sera pas associée à un processus spécifique, mais les fichiers ne seront accessibles qu’à un utilisateur spécifique (le même que celui utilisé par votre serveur Web pour être utile!), Ce qui pourrait suffire?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X