FrankH: Erstellung von Verzeichnis mit .htaccess und htpassword mit php

Ich möchte gerne einen FTP innerhalb einer Homepage integrieren.
Benötigte Features:

  • Verzeichnis (Ordner) anlegen
  • Zugriffsschutz anlegen (.htaccess und .htpasswd)
  • Files drin ablegen

Weiter:

  • Wenn man auf das Verzeichnis geht, sollen die Inhalte angezeigt werden.

Ziel: Einen Download für einen Kunden bereit stellen, für den man kein FTP-Programm
benötigt!

Folgende Probleme sind aufgetreten:
1. das Verzeichnis kann nach Erstellung nicht mehr gelöscht werden
2. ich kann keine Dateien darin per FTP einfügen

Was ich jetzt nicht weiss:
warum hat meine .htaccess Datei nach dem Erstellen den wert adfr(0644) statt adfrw(0644)
und den Besitzer/Gruppe 33 33 statt 1128 ...

  
  
$Unterverzeichnis     =   'files';  
$rootVerzeichnis      =   str_replace("isoonline/",'',$_SERVER["DOCUMENT_ROOT"]);  
$ZielVerzeichnis      =   p_leer($_REQEUST[$ZielVerzeichnis],$rootVerzeichnis.$Unterverzeichnis);  
  
  
if($_REQUEST['do'] == '1' ){  
  //Verzeichnis erstellen  
  echo "<br>Dieses Verzeichnis wurde erstellt: ";  
  echo $neueVerzeichnisUrl   =   "$ZielVerzeichnis/$_REQUEST[neuesVerzeichnis]";  
  echo "<br>";  
  
  mkdir ($neueVerzeichnisUrl ,0755 );  
  
   $testText=  
    'Ein kleiner Versuch';  
  
    $testDateiName = "test.htm";  
    $testDatei = fopen("$neueVerzeichnisUrl/$testDateiName","w+");  
    fwrite($testDatei, $testText);  
    fclose($testDatei);  
  
  //htaccess script!  
  function make_htaccess($user, $authName, $passwdFile="")  
{  
  
    if(empty($passwdFile))  
        $passwdFile=dirname(__FILE__);  
  
    $access .=    '# Datei für Verzeichnis /bilder' . "\n";  
    $access .=    'FancyIndexing On' . "\n";  
    $access .=    'AddDescription "HTML-Datei, anzeigbar" .htm .html' . "\n";  
    $access .=    'AddDescription "GIF-Grafik, anzeigbar" .gif' . "\n";  
    $access .=    'AddDescription "JPEG-Grafik, anzeigbar" .jpg' . "\n";  
    $access .=    'AddDescription "ZIP-Archiv, downloadbar" .zip' . "\n";  
    $access .=    'AuthType Basic' . "\n";  
    $access .=    'AuthName "' . $authName . '"' . "\n";  
    $access .=    'AuthUserFile ' . $passwdFile . '/.htpasswd' . "\n";  
    $access .=    'require user ' . $user . "\n";  
    //$handle = fopen(".htaccess","w");  
    //$htaccssName = ".htaccess";  
    $handle = fopen($passwdFile . '/.htaccess',"w+");  
    fputs($handle,$access);  
    fclose($handle);  
  
}  
  
  
function make_htpasswd($user, $passwd, $passwdFile="")  
{  
  
    if(empty($passwdFile))  
        $passwdFile=dirname(__FILE__);  
  
    $passwd = crypt($passwd);  
    $htpasswd = $user . ':' . $passwd . "\n";  
  
    $handle = fopen($passwdFile . '/.htpasswd',"w+");  
    fputs($handle,$htpasswd);  
    fclose($handle);  
  
}  
  
// Den Benutzernamen für den Login  
$user   = $_REQUEST[ftpUser];  
  
// Das Passwort für den Login  
$passwd = $_REQUEST[ftpPassword];  
  
// Der Text, der angezeigt wird wenn das Login-Fenster geöffnet wird.  
$authName = 'Meine geschütztes Verzeichnis';  
  
//Den kompletten Pfad zu der Datei .htpasswd, ohne abschließenden Slash (/)  
$passwdFile = "$neueVerzeichnisUrl";  
  
  
make_htaccess($user, $authName, $passwdFile);  
make_htpasswd($user, $passwd, $passwdFile);  
  
// unlink("crypt.php");  
  
  
  
  
  /*  
  //htaccess erstellen  
    $htaccessText=  
    "AuthUserFile $rootVerzeichnis/$Unterverzeichnis//.htpasswd".  
    "AuthGroupFile /dev/null".  
    "AuthName ByPassword".  
    "AuthType Basic".  
    "require valid-user";  
  
    $htaccssName = ".htaccess";  
    $htaccess = fopen("$neueVerzeichnisUrl/$htaccssName","w+");  
    fwrite($htaccess, $htaccessText);  
    fclose($htaccess);  
  
    //htpasswd erstellen  
    $htpasswdText=  
    "$_REQUEST[ftpUser]".  
    ":".  
    crypt($_REQUEST[ftpPassword],substr($_REQUEST[ftpPassword],0,2));  
  
    $htpasswdName = ".htpasswd";  
    $htpasswd = fopen("$neueVerzeichnisUrl/$htpasswdName","w+");  
    fwrite($htpasswd, $htpasswdText);  
    fclose($htpasswd);  
   */  
    //Testdatei erstellen  
        //htpasswd erstellen  
    $testText=  
    'Ein kleiner Versuch';  
  
    $testDateiName = "test.htm";  
    $testDatei = fopen("$neueVerzeichnisUrl/$testDateiName","w+");  
    fwrite($testDatei, $testText);  
    fclose($testDatei);  
  
}  
  
//Vorhandene Verzeichnisse ausgeben:  
echo "<p>Diese Verzeichnisse bestehen bereits in diesem Verzeichnis:<br>";  
$offen = opendir("$ZielVerzeichnis");  
      while ($file = readdir ($offen))  
      {  
        echo "<li><a href=\"$_SERVER[PHP_SELF]?ZielVerzeichnis=$ZielVerzeichnis/$file\">".$file."</a>  
                  <br>  
                  <a href=\"http://www.promicron.org/files/$file\">".$file.'</a>  
              </li>';  
      }  
      closedir($offen);  
?>  

  1. Tach!

    Folgende Probleme sind aufgetreten:

    1. das Verzeichnis kann nach Erstellung nicht mehr gelöscht werden

    Derjenige, der das Verzeichnis hat anlegen können, muss es auch löschen können. Beides sind Schreiboperationen im übergeordneten Verzeichnis, wofür die entspechenden Rechte benötigt werden.

    1. ich kann keine Dateien darin per FTP einfügen

    Das ist ein typisches Problem bei Hostern, mit PHP als Apache-Modul. In dem Fall läuft PHP unter der Kennung des Webservers und die FTP-Kennung des Anwenders ist eine andre, wobei dann die Zugriffsrechte über Gruppenzugehörigkeiten oder gar "Other" gelöst werden müssen. Beides ist gleichermaßen ungünstig, weil durch die Schreibrechte für den Apachen auch alle andere Mithostlinge Zugriff bekommen.

    Was ich jetzt nicht weiss:
    warum hat meine .htaccess Datei nach dem Erstellen den wert adfr(0644) statt adfrw(0644)
    und den Besitzer/Gruppe 33 33 statt 1128 ...

    Wer oder was ist adfr/adfrw? 33 ist vermutlich UID und GID vom Apachen, 1128 wird die deiner FTP-Kennung sein.

    Das Problem lässt sich sicherheitstechnisch einigermaßen ordentlich nur dann lösen, wenn PHP als (F)CGI unter eigener Kennung läuft, die dann auch gleichzeitig die FTP-Kennung (oder besser SFTP/SSH) ist. Wenn das für dich beim Hoster nicht konfigurierbar ist, dann ist der für das Projekt nicht brauchbar. Bei einem eigenen Server solltest du das entsprechend der dortigen Konfigurationsphilosophie ändern können.

    dedlfix.

    1. Tach!

      Post!

      Das Problem lässt sich sicherheitstechnisch einigermaßen ordentlich nur dann lösen, wenn PHP als (F)CGI unter eigener Kennung läuft, die dann auch gleichzeitig die FTP-Kennung (oder besser SFTP/SSH) ist.

      Ich vermute, das hat der Hoster, jedenfalls derjenige, der den Host konfigurierte, warum auch immer vermeiden wollen, damit ggf. hochgeladene Dateien ohne weitere Handlung via http abrufbar sind.

      Für FrankH:

      Mit FTP kann man, (so vom Server unterstützt ... was bei den unter Linux laufenden FTP-Servern in der Regel auch der Fall sein dürfte) neben den Rechten (chmod) auch die Eigentümer/Gruppenzugehörigkeit setzen.

      Wenn die Dateien per http hochgeladen werden sollen, so muss natürlich der www-run (uid 33) schreiben dürfen, wenn die Dateien per FTP hochgeladen sollen, der FTP-User (uid 1128).

      Das könnte für Dich ein Dilemma darstellen. Entweder kannst Du in einer shell (also via ssh) erweitere Rechte für das Verzeichnis mit setfacl setzen (PDF) oder Du musst das Verzeichnis für jeden betret-, les- und schreibbar (0777) machen, enthaltene Dateien lesbar (0666). (Hüte Dich davor, von den Kunden stammende Dateien mit chmod 777 ausführbar zu machen.)

      Achte aber hierbei auf Nebenwirkungen, letzteres kann zu erheblichen (Sicherheits-)Interessenkollisionen führen! (Soweit zum Dilemma.)

      Ich habe hier mal aus der Information "UID 1128" heraus spekuliert, dass es um Massenhosting geht und gehe im weiteren davon aus:

      In diesem Zusammenhang ist es bei derartigen Problemen (wir müssen einiges erraten, also spekulieren) immer eine gute Idee nach dem Studium der von diesem sicherlich angebotenen FAQ auch den Support des Hosters einzubeziehen. Manche Hoster sind froh, wenn diese gefragt werden bevor deren Server als Malwareschleuder in den Blacklists stehen und die können, weil die ihre Systeme kennen, auch die richtigen Antworten geben. Hat Dein Hoster keinen kostenlosen (und reagierenden) E-Mail-Support ist er irgendwie keine gute Wahl für Dein gutes Geld.

      Jörg Reinholz

      1. Tach!

        Das Problem lässt sich sicherheitstechnisch einigermaßen ordentlich nur dann lösen, wenn PHP als (F)CGI unter eigener Kennung läuft, die dann auch gleichzeitig die FTP-Kennung (oder besser SFTP/SSH) ist.
        Ich vermute, das hat der Hoster, jedenfalls derjenige, der den Host konfigurierte, warum auch immer vermeiden wollen, damit ggf. hochgeladene Dateien ohne weitere Handlung via http abrufbar sind.

        Warum sollten sie das nicht sein? Solange diese statischen Dateien welt-lesbar sind, ist doch alles bestens. Oder aber User und Apache sind in derselben Gruppe.

        Mit FTP kann man, (so vom Server unterstützt ... was bei den unter Linux laufenden FTP-Servern in der Regel auch der Fall sein dürfte) neben den Rechten (chmod) auch die Eigentümer/Gruppenzugehörigkeit setzen.

        Ja, wenn man root ist. Ansonsten ist es nicht möglich, einem anderen Benutzer die eigenen Dateien unterzuschieben, sonst könnte man wunderbar Quota-Mechanismen aushebeln -> einfach die Dateien im eigenen Verzeichnis jemand anderem geben und schon hat man wieder Platz -> aber so einfach macht Linux es einem auch wieder nicht.

        dedlfix.

        1. Tach!

          Post!

          Ich vermute, das hat der Hoster, jedenfalls derjenige, der den Host konfigurierte, warum auch immer vermeiden wollen, damit ggf. hochgeladene Dateien ohne weitere Handlung via http abrufbar sind.

          Warum sollten sie das nicht sein?

          Tja. Eine philosophische Frage - die offensichtlich der Hoster entschieden hat. Ich will nicht spekulieren, aber ich glaube, der verspricht sich davon einen "Sicherheitsgewinn". Womöglich ist der Server sogar so (schlecht) eingerichtet, dass DOCUMENT_ROOT per default gleich dem $HOME des (FTP-)Benutzers ist und womöglich sogar so schlecht, dass der Kunde das DOCUMENT_ROOT nicht umkonfigurieren kann. Man findet ja so Einiges bei den Anbietern.

          Mit FTP kann man, (so vom Server unterstützt ... auch die Eigentümer/Gruppenzugehörigkeit setzen.

          Ja, wenn man root ist.

          Ja. Stimmt. Denn ...

          sonst könnte man wunderbar Quota-Mechanismen aushebeln

          Damit hast Du durchaus Recht. Das würde aber wohl eher ein kleineres der entstehenden Probleme sein.

          Jörg Reinholz

  2. Hallo,

    Ich möchte gerne einen FTP innerhalb einer Homepage integrieren.

    deine Darstellung ist widersprüchlich, denn weiter unten wird deutlich, dass du eben *nicht* FTP willst, sondern HTTP. Wie auch immer, der Themenbereich HTML/XHTML ist in jedem Fall unpassend gewählt.

    Benötigte Features:

    • Verzeichnis (Ordner) anlegen
    • Zugriffsschutz anlegen (.htaccess und .htpasswd)
    • Files drin ablegen

    Bei FTP auf jeden Fall im Funktionsumfang enthalten, wobei "Zugriffsschutz anlegen" sich auf das Anlegen/Hochladen der beiden erforderlichen Dateien herunterbrechen lässt.

    • Wenn man auf das Verzeichnis geht, sollen die Inhalte angezeigt werden.

    Was meinst du mit "auf das Verzeichnis gehen"?

    Ziel: Einen Download für einen Kunden bereit stellen, für den man kein FTP-Programm benötigt!

    Ja, also nicht FTP, sagte ich ja schon.

    Folgende Probleme sind aufgetreten:

    1. das Verzeichnis kann nach Erstellung nicht mehr gelöscht werden

    Durch wen (welchen Benutzer)? Und ist es überhaupt leer?

    1. ich kann keine Dateien darin per FTP einfügen

    Meinst du an dieser Stelle wirklich FTP? - Wird wohl auch ein Problem der Benutzerrechte sein.

    Was ich jetzt nicht weiss:
    warum hat meine .htaccess Datei nach dem Erstellen den wert adfr(0644) statt adfrw(0644) und den Besitzer/Gruppe 33 33 statt 1128 ...

    UID 33 ist auf vielen Systemen www-data, also der typische User, unter dem der Webserver läuft. Logisch, dass die Datei diesem Benutzer gehört, wenn der sie erzeugt hat. Und 0644 heißt, jeder darf sie lesen, aber nur der Besitzer auch schreiben. Ist 1128 etwa der deinem Account zugeordnete FTP-User?

    $Unterverzeichnis     =   'files';

    $rootVerzeichnis      =   str_replace("isoonline/",'',$_SERVER["DOCUMENT_ROOT"]);
    $ZielVerzeichnis      =   p_leer($_REQEUST[$ZielVerzeichnis],$rootVerzeichnis.$Unterverzeichnis);

      
    Wieso verwendest du $\_REQUEST? Möchtest du dich nicht auf $\_GET oder $\_POST festlegen?  
      
    
    > ~~~php
    
    if($_REQUEST['do'] == '1' ){  
    
    >   //Verzeichnis erstellen  
    >   echo "<br>Dieses Verzeichnis wurde erstellt: ";  
    >   echo $neueVerzeichnisUrl   =   "$ZielVerzeichnis/$_REQUEST[neuesVerzeichnis]";  
    >   echo "<br>";  
    >   
    >   mkdir ($neueVerzeichnisUrl ,0755 );
    
    

    Na du bist ja lustig. Meldest den Vollzug schon, bevor du überhaupt versuchst, das Verzeichnis anzulegen. Und ob es gelungen ist, überprüfst du nicht einmal.

    $testText=

    'Ein kleiner Versuch';

    $testDateiName = "test.htm";
        $testDatei = fopen("$neueVerzeichnisUrl/$testDateiName","w+");
        fwrite($testDatei, $testText);
        fclose($testDatei);

      
    Von "Versuch" wollen wir hier auch nicht reden, wenn du nicht einmal den Erfolg deiner Aktionen abfragst. Das absolute Minimum sollte sein, das Ergebnis von fopen() zu prüfen (sollte non-zero sein).  
      
    
    > ~~~php
    
    // Den Benutzernamen für den Login  
    
    > $user   = $_REQUEST[ftpUser];  
    >   
    > // Das Passwort für den Login  
    > $passwd = $_REQUEST[ftpPassword];
    
    

    FEHLER: Du meinst sicher die Stringkonstanten 'ftpUser' und 'ftpPassword' anstatt der benannten Konstanten ftpUser und ftpPassword, was PHP mit der Ausgabe einer Notice-Meldung auch kritisiert. Die Bezeichnungen sind auch irreführend, weil es sich ja gerade *nicht* um FTP handelt.

    //Den kompletten Pfad zu der Datei .htpasswd, ohne abschließenden Slash (/)

    $passwdFile = "$neueVerzeichnisUrl";

      
    Wozu einen einzelnen Wert, der sowieso ein String ist, nochmal in einen String einbetten?  
      
    
    > ~~~php
    
    //Vorhandene Verzeichnisse ausgeben:  
    
    > echo "<p>Diese Verzeichnisse bestehen bereits in diesem Verzeichnis:<br>";  
    > $offen = opendir("$ZielVerzeichnis");
    
    

    Nochmal der Unfug mit dem String im String. Außerdem: Warum beginnst du an der Stelle ein p-Element, obwohl IMO eine Überschrift viel passender wäre? Abgesehen davon, dass du das p-Element nirgends wieder abschließt.

    while ($file = readdir ($offen))

    {
            echo "<li><a href="$_SERVER[PHP_SELF]?ZielVerzeichnis=$ZielVerzeichnis/$file">".$file."</a>
                      <br>
                      <a href="http://www.promicron.org/files/$file">".$file.'</a>
                  </li>';
          }
          closedir($offen);
    ?>

      
    Was hat es mit den beiden Links auf sich, die du da pro Datei/Verzeichnis ausgibst?  
      
    Und was war jetzt eigentlich deine Frage?  
      
    So long,  
     Martin  
    
    -- 
    Es gibt Tage, da gelingt einem einfach alles.  
    Aber das ist kein Grund zur Sorge; das geht vorbei.  
    Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(