Hilfe bei News Seite mit Backend [Internem Bereich]


#1
Hallo Foren Nutzer,
ich freue mich nun hier meine Frage stellen zu dürfen und hoffe, dass ich dies im richtigen bereich mache, erstmal kur als Information, ich bin realtiv neu in php eingestiegen und habe kaum Kentnisse, ich bin 1-2 Tutorials durchgegangen und habe mich mit den Grundlagen vertraut gemacht.

Nun zu meiner Frage: Vor ca. 2 Wochen hat sich ein Freund von mir gemeldet, welcher einen eigenen GameServer betreibt, und hat mich gefragt, ob es möglich wäre, dass ich für ihn eine News Seite erstelle.
Diese Seite soll ein Frondend sowie ein Backend [Internen Bereich] besitzen.

Nun habe ich mir einen Editor Rausgesucht: CK Editor 4 (nicht meine erste wahl, bin aber damit zufrieden)

Das einbinden war auch kein Problem, Registrierung und Login Seite waren schon vorhanden, habe ich dann einfach übernommen.
Jetzt kommt aber mein Problem, ich habe in einem anderen Forum um Rat gebeten, da sagt mir aber jeder was anderes, daher wende ich mich nun hier an euch.

Ich würde gerne den inhalt aus dem editor über den vorhandenen Save Button an eine Datenbank übergeben, welche dann die Daten auf der "News Seite" bzw. im Frondend ausgibt. Das ganze Ding habe ich auch geschrieben und es funktioniert, nur gibt es da noch 1 Problem, das ganze sieht mir nicht Sauber und sicher aus, könnte mir dabei jemand helfen und mir sagen, was ich noch ändern könnte.

Hier erstmal meine beiden Seiten:
internal.php
PHP:
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");

$user = check_user();

include("templates/header.inc.php");
?>

<div class="container main-container">

<h1>Herzlich Willkommen!</h1>

Hallo <?php echo htmlentities($user['username']); ?>,<br>
Herzlich Willkommen im internen Bereich!<br><br>

<form action="index.php" method="post">
    <textarea name="editor1" id="editor1" rows="10" cols="80">
        This is my textarea to be replaced with CKEditor.
    </textarea>
    <input type="submit">
    <input type="hidden" name="username" value="<?php echo $user['username'];?>">
    <script>
        CKEDITOR.replace( 'editor1', {
        language: 'de',
        });
    </script>
</form>

</div>
<?php
include("templates/footer.inc.php")
?>
index.php
PHP:
<?php
session_start();
require_once("inc/config.inc.php");
require_once("inc/functions.inc.php");
include("templates/header.inc.php")
?>
    <!-- Main jumbotron for a primary marketing message or call to action -->
    <div class="jumbotron">
      <div class="container">
        <h1>Nexus Scripts</h1>
        <p>Herzlich Willkommen zum Login & Register -script.
        
        Das Design wurde mittels <a href="http://getbootstrap.com" target="_blank">Bootstrap v3.3.6</a> erstellt.<br><br>
        
        </p>
        <p><a class="btn btn-primary btn-lg" href="register.php" role="button">Jetzt registrieren</a></p>
      </div>
    </div>

    <!-- Mit dem Editor erstellter Text -->
        <?php
          if (isset($_POST['editor1'])) {
            $statement = $pdo->prepare("INSERT INTO posts (created_at, created_by, html_code) VALUES (?, ?, ?)");
            $statement->execute(array(date('Y-m-d H:i:s'), $_POST['username'], $_POST['editor1']));
          }

          $statement = $pdo->prepare("SELECT * FROM posts ORDER BY id DESC");
          $result = $statement->execute();
          while($row = $statement->fetch()) {
            echo '<div class="jumbotron">';
            echo '<div class="container">';
            echo "Erstellt am: ".$row['created_at']."<br/>";
            if (isset($row['updated_at'])) {
              echo "Editiert am: ".$row['updated_at']."<br/>";
            }
            echo "Geschrieben von: ".$row['created_by']."<br/>";
            echo "".$row['html_code']."";
            echo '</div>';
            echo '</div>';
          }
        ?>

    <div class="container">
      <!-- Example row of columns -->
      <div class="row">
        <div class="col-md-4">
          <h2>Features</h2>
          <ul>
              <li>Registrierung & Login</li>
              <li>Interner Mitgliederbereich</li>
              <li>Neues Zusenden eines Passworts</li>
              <li>Programmcode leicht verständlich und optimiert</li>
          </ul>
        
        </div>
        <div class="col-md-4">
          <h2>Dokumentation</h2>
          <p>Dies ist das neue Webinterface [Backend] für die Homepage, welches neue und tolle funktionen für die Benutzer bereit hält.</p>
          <p><a class="btn btn-default" href="#" target="_blank" role="button">Weitere Informationen &raquo;</a></p>
       </div>
        <div class="col-md-4">
          <h2>Webhosting</h2>
          <p>Für das LoginScript ist ein PHP fähiger Webserver von nöten. Auf dieser Website werden die verschiedenen Webhosting-Angebote ausführlich getest, damit ihr den idealen Webspace für eure Website findet.</p>
          <p><a class="btn btn-default" href="http://www.webhosterwissen.de" target="_blank" role="button">Weitere Informationen &raquo;</a></p>
        </div>
      </div>
    </div> <!-- /container -->
 
<?php
include("templates/footer.inc.php")
?>
Zudem ist eine Datenbank wie folgt angelegt worden:
SQL:
CREATE TABLE IF NOT EXISTS `posts` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL,
  `created_by` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `html_code` Text COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Hoffe einer kann mir weiter helfen.

mfg Sullaysur
 

ComFreek

Mod | @comfreek
Moderator
#2
htmlentities($user['username']);
Ob htmlentities ohne Optionen im zweiten Argument ausreicht, kann ich dir nicht sagen. Im Zweifel würde das noch einmal googeln und in eine Hilfsfunktion auslagern, falls dem so ist.

Zwar keine Antwort auf deine Frage, aber dein Code ist anfällig für XSS.Tatsächlich war das deine Frage :)
<input type="hidden" name="username" value="<?php echo $user['username'];?>">
und weitere ähnliche Stellen, wo du 'username' oder 'created_by' asugibst.

Zudem ist eine Datenbank wie folgt angelegt worden:
SQL:
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL,
`created_by` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`html_code` Text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Das "created_by" deutet darauf hin, dass dein DB-Schema nicht normalisiert ist. Höchste Normalform ist nicht immer ein gutes Ziel für die Praxis, aber hier würde ich stark empfehlen, "created_by" durch einen Fremdschlüssel auf deine Nutzertabelle zu ersetzen.

Ist dir bewusst, dass jeder, der Beiträge schreiben kann, auch beliebigen HTML-Code auf der Seite anzeigen lassen kann? D.h. er kann beliebig die Seite unnutzbar machen, Besucher auf andere gefährliche Seiten weiterleiten, jede Eingabe abfangen etc.

Ansonsten gefällt mir, dass du Prepared Statements einsetzt! Bravo!
 
#3
Ob htmlentities ohne Optionen im zweiten Argument ausreicht, kann ich dir nicht sagen. Im Zweifel würde das noch einmal googeln und in eine Hilfsfunktion auslagern, falls dem so ist.
Doch, das funktioniert soweit ganz gut, habe zumindestens keinen fehler bekommen.


und weitere ähnliche Stellen, wo du 'username' oder 'created_by' asugibst.
Wie kann ich diese stellen sicherer machen?


aber hier würde ich stark empfehlen, "created_by" durch einen Fremdschlüssel auf deine Nutzertabelle zu ersetzen.
Heißt also ich sollte auf meiner nutzertabelle created_by erstellen und in der posts tabelle als Fremdschlüssel hinzufügen?


Ist dir bewusst, dass jeder, der Beiträge schreiben kann, auch beliebigen HTML-Code auf der Seite anzeigen lassen kann?
Ja das ist mir bewusst, aber die nutzer sollen nur von einem Administrator regestriert werden können, da nur Teammitglieder und vertrauenswürdige Personen beiträge schreiben dürfen.


D.h. er kann beliebig die Seite unnutzbar machen, Besucher auf andere gefährliche Seiten weiterleiten, jede Eingabe abfangen etc.
Wie könnte man das Verhindern, bzw hast du da einen Tipp?

Zudem Danke ich für deine Sehr hilfreiche Nachricht, würde mich über eine Antwort freuen.

mfg Sullaysur
 

ComFreek

Mod | @comfreek
Moderator
#4
Doch, das funktioniert soweit ganz gut, habe zumindestens keinen fehler bekommen.
Das "ausreicht" bezog sich nicht auf die Funktionstüchtigkeit, sondern auf die Sicherheit. Es gibt viel zu viele mögliche Angriffseingaben, um alle manuell zu testen. Lieber im Internet nach einer akzeptierten Lösung suchen.


Wie kann ich diese stellen sicherer machen?
Google sagt dir das sofort bei Suche nach "php echo in html attribute". htmlentities mit ENT_QUOTES und ENT_HTML5. OWASP ist übrigens eine gute Quelle für Sicherheitslücken, die hier genannte ist etwa OWASP/CheatSheetSeries. (D.h. aber nicht, dass du deine eigene Funktion programmieren sollst, die genau das macht, was dort steht. Immer eine bekannte und getestete Bibliothek nutzen! htmlentities fällt hier in die PHP-"Standardbibliothek")

Heißt also ich sollte auf meiner nutzertabelle created_by erstellen und in der posts tabelle als Fremdschlüssel hinzufügen?
Nein. Ich empfehle dir aber, dir ein praxisnahes Tutorial für Normalisierung herauszusuchen. Eigentlich sollte das auch in jedem Einführungsartikel/-buch zu Datenbanken stehen. In kurz: In der Posts-Tabelle created_by vom selben Typ machen wie der Primary Key in der Nutzertabelle und dann als Fremdschlüssel verweisen lassen.

Ja das ist mir bewusst, aber die nutzer sollen nur von einem Administrator regestriert werden können, da nur Teammitglieder und vertrauenswürdige Personen beiträge schreiben dürfen.
Ich weiß gar nicht, wie CMSe wie Joomla, Typo3 usw. das machen. Laut Entering raw HTML in editors - Joomla! Documentation (bezieht sich allerdings auf eine ältere Joomla-Version) wird beim Erstellen des Posts HTML wahlweise gefiltert. Im Endeffekt musst du aber wissen, ob du jedem Nutzer, der Beiträge schreiben/verändern darf, trauen kannst.

Wie könnte man das Verhindern, bzw hast du da einen Tipp?
Nein, das kannst du nur verhindern, indem du HTML filterst, siehe letzten Absatz. Für HTML Filtering gibt es auch bekannte Libraries für PHP, einfach mal nach "html sanitize library" googeln ;) Aber wenn du beliebiges HTML erlauben möchtest, dann ist das unzertrennlich mit diesem Risiko verbunden.
 

Neue Beiträge