Logo Oracle Deutschland   Application Express Community

Cross Site Scripting und APEX Berichte. Das sollten Sie wissen.

Stand APEX-Version Datenbankversion
Mai 2016 ab APEX 5.0 ab 11.1

Sicherheit ist für alle Web-Anwendungen ein wichtiges Thema - so auch für Application Express. In diesem Tipp geht es um das Thema Cross Site Scripting (XSS) im Zusammenspiel mit Berichten (Reports). In der Praxis werden Berichte vielfältig eingesetzt, und oft werden die Darstellungsmöglichkeiten des Browsers voll ausgenutzt. Wie sicherheitsrelevant das ist, schauen wir uns in diesem Tipp an.

Wir beginnen mit einem einfachen Bericht auf die wohlbekannt Tabelle EMP - der sieht dann wie in Abbildung 1 aus.

Ein einfacher, interaktiver Bericht

Abbildung 1: "Ein einfacher, interaktiver Bericht"

Eine typische Anforderung ist dann, die Spalte EMP_COMMENT rot einzufärben. Oft wird das mit einer veränderten SQL-Abfrage realisiert ...

select 
  empno,
  ename,
  job,
  hiredate,
  '<span style="color: red">' || emp_comment || '</span>' as emp_comment
from emp

... was zunächst zu einer Ausgabe wie in Abbildung 2 führt.

Versuch, die Spalte SAL rot einzufärben

Abbildung 2: Versuch, die Spalte SAL rot einzufärben

Nun wird noch die Einstellung Escape Special Characters für die Spalte auf No gestellt und das Ergebnis ist erreicht (Abbildung 3).

Das Ergebnis

Abbildung 3: Das Ergebnis

Allerdings hat die Anwendung nun schon eine mögliche Cross Site Scripting Lücke. Diese entstehen, wenn der Browser Javascript zur Ausführung bringt, welches der Anwendungsentwickler gar nicht vorgesehen hatte. In unserem Beispiel gehen wir davon aus, dass die Spalte EMP_COMMENT nur einfachen Text enthält - aber angenommen, ein anderer (bösartiger) Anwender macht folgenden Eintrag - das könnte sogar über ein völlig anderes Tool erfolgen.

<script>alert("Das ist Javascript");</script>

Der nächste Aufrufer der Seite würde dann die folgende Ausgabe sehen.

Cross Site Scripting in Aktion

Abbildung 4: Cross Site Scripting in Aktion

Dieses Beispiel ist zwar lästig, aber noch harmlos. Viel gefährlicher wird es, wenn mit dem <script> Tag externer Code von fremden Servern heruntergeladen wird. Solcher Code könnte Inhalte (Daten) der Seite auslesen und über das Internet an den Server des Angreifers schicken - oder andere, gefährliche Dinge tun.

Die Art und Weise, wie die Spalte EMP_COMMENT rot eingefärbt wurde, ist also nicht zu empfehlen. Bedeutet das nun, dass man Daten in Berichten nicht mehr dynamisch formatieren darf oder kann ...? Nein, mitnichten. Es gibt allerdings einen wesentlich sichereren Weg, dies umzusetzen.

  • Stellen die die Einstellung Escape Special Characters in der Berichtsspalte auf Yes zurück - damit ist der Bericht wieder sicher.
  • Nehmen Sie das HTML-Markup aus der SQL-Abfrage heraus und selektieren Sie die Spalte ganz normal
  • Navigieren Sie im Page Designer zur Berichtsspalte, im Property Editor zum Attribut HTML Expression und hinterlegen Sie dort folgendes.
    <span style="color: red">#EMP_COMMENT#</span>
    
Attribut HTML Expression einer Berichtsspalte

Wenn Sie die Berichtsspalte nun ansehen, ist die Spalte Comments immer noch rot eingefärbt, die Nutzereingabe wird aber maskiert und bleibt damit ungefährlich: Dieser Bericht ist sicher vor Cross-Seite-Scripting Attacken.

Dieser Bericht ist sicher

Abbildung 5: Dieser Bericht ist sicher

Doch mit solch einfachen Anforderungen ist es oft nicht getan - denken wir also ein wenig weiter: Die Kommentare werden rot eingefärbt, wenn das Gehalt größer als 3000 ist, orange zwischen 2000 und 3000 und grün unter 1000. Das ist ein komplexer Ausdruck, den man mit der HTML-Formatmaske so nicht abbilden kann - ein SQL CASE Ausdruck muss her. Bevor Sie jedoch nun jedoch wieder HTML-Markup in der SQL-Query generieren, denken Sie nochmals nach: Es braucht doch kein dynamisches HTML-Markup; nur die Farben selbst (!) müssen generiert werden. Schauen Sie sich die folgende Abfrage an.

select 
  empno,
  ename,
  job,
  hiredate,
  emp_comment,
  case
    when sal < 2000 then                'green'
    when sal between 2000 and 3000 then 'orange'
    else                                'red'
  end as comment_color
from emp

Die neue Spalte COMMENT_COLOR stellen Sie auf Hidden, so dass man sie im Bericht nicht sehen kann. Als HTML Expression für die Spalte EMP_COMMENT nehmen Sie nun folgendes:

<span style="color: #COMMENT_COLOR#">#EMP_COMMENT#</span>

Das Ergebnis sieht dann wie in Abbildung 6 aus - sie sehen: Auch verschiedene Farben bzw. CSS-Direktiven sind kein Problem - in den Tabellenspalten enthaltene HTML-Sonderzeichen werden weiterhin maskiert - der Bericht bleibt sicher.

Bericht mit konditionaler Darstellung - immer noch sicher

Abbildung 6: Bericht mit konditionaler Darstellung - immer noch sicher

Mit diesem Ansatz kommt man bei der Berichtsformatierung wirklich sehr weit - versuchen Sie am besten, Ihre Anforderungen immer so umzusetzen. Allerdings gibt es auch Situationen, wo die HTML Expression alleine nicht mehr ausreicht. Das ist dann der Fall, wenn die zu erzeugenden HTML-Tags selbst dynamisch generiert werden müssen. Angenommen, die Spalte EMP_COMMENT soll, wenn das Gehalt größer als 4500 ist, eine deutlich sichtbare Nachricht enthalten - außerdem soll der Kommentar dann eingerahmt werden. Das ist zugegebenermaßen eine etwas konstruierte Anforderung, dennoch wollen wir sie umsetzen. Versuchen wir es zuerst, wie gerade gelernt: In der SQL-Query wird allein die Warnung generiert.

select 
  empno,
  ename,
  job,
  hiredate,
  emp_comment,
  case
    when sal < 2000 then 'green'
    when sal between 2000 and 3000 then 'orange'
    else 'red'
  end as comment_color,
  case
    when sal > 4500 then 'Hohes Gehalt'
    else null
  end as comment_warn
from emp

Im Attribut HTML Expression machen wir die Formatierung:

<div style="border: 1px solid black;">
  <h1>#COMMENT_WARN#</h1>
  <span style="color: #COMMENT_COLOR#">#EMP_COMMENT#</span>
</div>

Die Spalte COMMENT_WARN machen wir wiederum unsichtbar (Hidden). Starten Sie die Seite und schauen Sie das Ergebnis an.

Weiterer Bericht mit konditionaler Darstellung - es ercheinen auch leere Rahmen

Abbildung 7: Weiterer Bericht mit konditionaler Darstellung - es ercheinen auch leere Rahmen

Dieses Ergebnis ist nicht ganz so, wie wir es erhofft haben. Alle Kommentare sind nun eingerahmt, außerdem sieht man in den Zeilen ohne Warnung deutlich den freien Platz für dieselbe.

Grund ist, dass das HTML der Formatmaske immer dargestellt wird - auch ohne Nachricht ist das HTML-Tag <h1> enthalten; es ist nur leer. In diesem Fall braucht es dynamisches HTML-Markup, welches in der SQL Abfrage erzeugt werden muss. Um jedoch nicht wieder eine Cross-Site-Scripting Lücke einzuführen, werden die eigentlichen Inhalte der Tabellenspalten mit der Funktion APEX_ESCAPE.HTML "behandelt". Danach kann die Einstellung Escape Special Characters gefahrlos auf No gestellt werden. Hinterlegen Sie also die folgende SQL-Abfrage.

select 
  empno,
  ename,
  job,
  hiredate,
    case 
      when sal > 4500 then '<div style="border: 1px solid black;"><h1>Hohes Gehalt</h1>'
      else                 '<div>'
    end || 
    '<span style="color: ' || 
    case
      when sal < 2000                then 'green'
      when sal between 2000 and 3000 then 'orange'
      else                                'red'
    end || '">' ||
    apex_escape.html( emp_comment ) ||
    '</span></div>' as emp_comment
from emp

Das Ergebnis ist wiederum sicher (erkennbar an der Ausgabe <script> ...), obwohl Escape Special Characters auf No gestellt wurde. Grund ist, dass die Inhalte aus der Tabelle mit APEX_ESCAPE.HTML esplizit maskiert wurden. Das übrige HTML-Markup besteht aus statischen, in der Query kodierten HTML-Tags. Wann immer Sie in SQL-Abfragen oder PL/SQL Code dynamisches HTML-Markup generieren und Escape Special Characters auf No stellen, behandeln Sie die unsichere Eingaben des Endbenutzers mit den Prozeduren von APEX_ESCAPE .

Sichere Berichtsausgabe trotz komplett dynamischem HTML

Abbildung 8: Sichere Berichtsausgabe trotz komplett dynamischem HTML

Bleibt noch die letzte Variante: Angenommen, die Spalte EMP_COMMENT wird von einem Rich Text Editor mit HTML-Code befüllt - HTML-Tags wie <b> oder <i> sollen also entsprechend dargestellt werden. Mit unserem aktuellen Setup werden die Tags maskiert - aus Sicherheitsgründen wollten wir das ja auch genau so haben.

Alle HTML-Tags werden maskiert - auch ungefährliche

Abbildung 9: Alle HTML-Tags werden maskiert - auch ungefährliche

Nicht nur das Tag <script> gefährtlich, sondern auch <iframe>; denn auch dieses lädt Inhalte von einer URL, beispielsweise von der eines fremden Servers. <img> ist ebenfalls sicherheitsrelevant; es lädt ein externes Bild - und mit der Bild-URL lassen sich Daten zu einem Server übertragen. Tags wie <b> oder <i> sind aber definitiv ungefährlich.

APEX_ESCAPE.HTML_WHITELIST arbeitet wie APEX_ESCAPE.HTML, maskiert die HTML-Tags, die in der Whitelist enthalten sind (also ungefährliche Tags), aber nicht. Standardmäßig sind das:

<h1>,</h1>,<h2>,</h2>,<h3>,</h3>,<h4>,</h4>,<p>,</p>,<b>,</b>,<strong>,</strong>,<i>,</i>,<ul>,</ul>,<ol>,</ol>,<li>,</li>,<br />,<hr/>

Mit dem Parameter p_whitelist_tags lässt sich eine eigene Tag-Whitelist anwenden - seien Sie hier aber entsprechend vorsichtig. Probieren wir dies für unsere obige SQL-Abfrage aus.

select 
  empno,
  ename,
  job,
  hiredate,
    case 
      when sal > 4500 then '<div style="border: 1px solid black;"><h1>Hohes Gehalt</h1>'
      else                 '<div>'
    end || 
    '<span style="color: ' || 
    case
      when sal < 2000                then 'green'
      when sal between 2000 and 3000 then 'orange'
      else                                'red'
    end || '">' ||
    apex_escape.html_whitelist( emp_comment ) ||
    '</span></div>' as emp_comment
from emp

Das Ergebnis sieht wie in Abbildung 10 aus.

Sichere Berichtsausgabe bei gleichzeitiger Berücksichtigung von HTML-Markup

Abbildung 10: Sichere Berichtsausgabe bei gleichzeitiger Berücksichtigung von HTML-Markup

Abbildung 10 zeigt sicherlich das komplexeste Beispiel, welches aber immer noch sicher gegenüber Cross-Site Scripting Attacken ist. Ein genereller Leitfaden zur Implementierung sicherer Berichte lässt sich sehr leicht herleiten.

  1. Belasse Escape Special Characters, wo immer möglich, auf Yes.
    • Realisiere HTML-Markup in der Berichtsausgabe mit dem Spaltenattribut HTML Expression.
    • Führe bei Bedarf zusätzliche, versteckte Spalten ein.
  2. Stelle Escape Special Characters nur dann auf No, wenn Deine Anforderung mit HTML Expression absolut nicht realisierbar ist.
    • Stelle sicher, dass alle Tabellenspalten mit APEX_ESCAPE behandelt werden.
    • Nimm APEX_ESCAPE.HTML, wenn keinerlei Markup in der Ausgabe erwünscht ist.
    • Nimm APEX_ESCAPE.HTML_WHITELIST, wenn bestimmtes Markup (Fett, Kursiv) in der Ausgabe erwünscht ist.
    • Nimm APEX_ESCAPE.HTML_ATTRIBUTE, wenn die Tabellenspalte ein HTML-Attribut sein soll.
  3. Stelle auf gar keinen Fall Escape Special Characters auf No, ohne gleichzeitig in der Abfrage APEX_ESCAPE zu verwenden.

Beachtet man diese einfachen Regeln, so lässt sich jeder Bericht gegen Cross-Site-Scripting sichern - und das, ohne das man auch nur den kleinsten Abstrich bei der Formatierung machen muss. Dieses Thema ist in jeder APEX-Anwendung auf fast jeder Seite relevant - probieren Sie es aus und machen Sie Ihre Berichte sicher.

Zurück zur Community-Seite