
ABAP - Escape
Schauen wir uns in diesem Artikel einmal im Detail verschiedene Escape Varianten an, die du für die ABAP Entwicklung und Sicherheit im System benötigst.
Inhaltsverzeichnis
In diesem Artikel schauen wir uns die Escape Funktion an und prüfen in einigen Details, wieso bisherige Beispiel und klassische Funktionen nicht mehr genutzt werden sollten.
Einleitung
In der Webentwicklung gehört es zum gängigen Standard, dass Eingaben von außen überprüft und behandelt werden, damit keine Steuerzeichen auf der Datenbank landen oder im schlimmsten Fall für eine SQL Injection verwendet werden. Ebenso werden neben Eingaben, auch zum Beispiel eine URL maskiert, da bestimmte Zeichen nicht erlaubt sind, aber vielleicht benötigt werden. Zum Beispiel kann ein kaufmännisches Und (&) in einem Parameter übergeben werden, da es aber auch ein HTML Steuerzeichen ist, muss es deshalb ersetzt werden.
Grundsätzlich handelt es sich hierbei nicht um ein Tutorial, wie du die Sicherheit in deinem Code verbesserst. Wir möchten damit Aufmerksamkeit für die Wichtigkeit des Themas setzen und dir den ESCAPE Befehl näherbringen.
Klassisch
In der klassischen ABAP Entwicklung kam daher die Methode ESCAPE_URL der Klasse CL_HTTP_UTILITY zum Einsatz, um die URL umzuwandeln. Führen wir allerdings heute eine Sicherheitsprüfung auf einem Objekt durch, dann erhalten wir für einige Objekte und Klassen eine Fehlermeldung.
Hierzu haben wir den folgenden Demo Code verwendet, um die Meldung durch das ABAP Test Cockpit zu erzeugen. Die Prüfung überprüft die Verwendung der ESCAPE Methoden aus den Objekten CL_HTTP_UTILITY, CL_HTTP_SERVER und CL_HTTP_CLIENT.
DATA(some_url) = `https://software-heroes.com/authors`.
DATA(escaped_url) = cl_http_utility=>escape_url( some_url ).
escaped_url = cl_web_http_utility=>escape_url( some_url ).
Hinweis: Allerdings gibt es hier noch eine Unschärfe in der Prüfung. Mit ABAP Cloud wurde die neue freigegebene API Klasse CL_WEB_HTTP_UTILITY implementiert. Diese ruft 1:1 die Methode ESCAPE_URL auf, erzeugt aber keine Fehlermeldung bei der Sicherheitsprüfung.
Escape
Schauen wir uns nun in diesem Kapitel die neue ESCAPE Funktion in ABAP an, die nun direkt in die Sprache integriert wurde. Die Dokumentation findest du im letzten Teil dieses Artikels, wenn du direkt die SAP Help anschauen willst.
Konstanten
Für die Formatierung der Ausgabe benötigst du die Konstanten aus der Klasse CL_ABAP_FORMAT, hier kannst du dir alle Konstanten anschauen die mit "E", wie Escape, beginnen.
Damit können aktuell mit ESCAPE die folgenden Szenarien abgedeckt werden:
- Markup und Javascript
- URLs und URIs
- JSON
- REGEX
- String Templates
- XSS (Cross Site Scripting)
URL
Wollen wir zum Beispiel die Methode ESCAPE_URL austauschen, dann müssten wir die Konstante E_URI_FULL_LC aus der Klasse als Format verwenden. Damit ergibt sich 1:1 dasselbe Ergebnis. Damit würde das Statement wie folgt aussehen:
DATA(escaped_function) = escape(
val = plain_url
format = cl_abap_format=>e_uri_full_lc ).
Aktuell gibt es für URL und URIs verschiedene Varianten, die auch unterschiedliche Zeichen in der URL austauschen. Dazu führen wir einmal alle Varianten aus und schauen uns die Unterschiede an.
String
Wie sieht es eigentlich mit String Templates aus? An einer Ausgabe ans Frontend oder in eine Datei kann doch nicht viel Schieflaufen. Grundsätzlich ja, wenn hier Steuerungszeichen für die String Templates verwendet werden, können zusätzliche Variablen und Inhalte ausgegeben werden, auf die der User vielleicht keinen Zugriff hat. Daher gibt es auch in diesem Bereich die Möglichkeit einen Escape durchzuführen.
DATA(template_string) = `This is a { Template } String in a |Box| `.
template_string &&= cl_abap_char_utilities=>cr_lf.
template_string &&= cl_abap_char_utilities=>horizontal_tab.
template_string &&= cl_abap_char_utilities=>newline.
template_string &&= ` End of text`.
DATA(escaped_string) = escape( val = template_string
format = cl_abap_format=>e_string_tpl ).
Im Beispiel oben haben wir unterschiedliche Steuerungszeichen der String Templates verwendet, aber auch Steuerungszeichen, um die Ausgabe zu verändern, wie einen Tabulator oder einen Zeilenumbruch. Nach der Durchführung des Escapes, geben wir beide Strings in die Konsole aus.
Demos
Bist du noch auf einem On-Prem System unterwegs, dann gibt es zahlreiche Demo-Reports, die du ausführen kannst, um dir das Ergebnis und Beispiele anzuschauen. Leider funktionieren diese Varianten in der Public Cloud nicht mehr, hier sollte SAP eine andere Möglichkeit für die Demos zur Verfügung stellen.
Vollständiges Beispiel
Hier findest du noch einmal das vollständige Beispiel aus dem heutigen Artikel. Da wir hier auch immer einen Vergleich mit der alten API von SAP machen, kann das Beispiel nur in einem On-Prem System komplett verwendet werden.
CLASS zcl_bs_demo_escape DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
CONSTANTS plain_url TYPE string VALUE `https://swh.com/c-r-v?repo='TIER3'&object=RFC_READ*`.
METHODS atc_check
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS escape_url
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS escape_url_compare
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS escape_string
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_escape IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
atc_check( out ).
escape_url( out ).
escape_url_compare( out ).
escape_string( out ).
ENDMETHOD.
METHOD atc_check.
DATA(some_url) = `http://`.
DATA(escaped_url) = cl_http_utility=>escape_url( some_url ).
escaped_url = cl_web_http_utility=>escape_url( some_url ).
out->write( some_url ).
out->write( escaped_url ).
ENDMETHOD.
METHOD escape_url.
DATA(escaped_classic) = cl_http_utility=>escape_url( plain_url ).
DATA(escaped_function) = escape( val = plain_url
format = cl_abap_format=>e_uri_full_lc ).
out->write( escaped_classic ).
out->write( escaped_function ).
ENDMETHOD.
METHOD escape_url_compare.
out->write( |Original : { plain_url }| ).
out->write( |E_URL : { escape( val = plain_url
format = cl_abap_format=>e_url ) }| ).
out->write( |E_URL_FULL : { escape( val = plain_url
format = cl_abap_format=>e_url_full ) }| ).
out->write( |E_URI : { escape( val = plain_url
format = cl_abap_format=>e_uri ) }| ).
out->write( |E_URI_FULL : { escape( val = plain_url
format = cl_abap_format=>e_uri_full ) }| ).
out->write( |E_URI_1 : { escape( val = plain_url
format = cl_abap_format=>e_uri_1 ) }| ).
out->write( |E_URI_LC : { escape( val = plain_url
format = cl_abap_format=>e_uri_lc ) }| ).
out->write( |E_URI_FULL_LC: { escape( val = plain_url
format = cl_abap_format=>e_uri_full_lc ) }| ).
ENDMETHOD.
METHOD escape_string.
DATA(template_string) = `This is a { Template } String in a |Box| `.
template_string &&= cl_abap_char_utilities=>cr_lf.
template_string &&= cl_abap_char_utilities=>horizontal_tab.
template_string &&= cl_abap_char_utilities=>newline.
template_string &&= ` End of text`.
DATA(escaped_string) = escape( val = template_string
format = cl_abap_format=>e_string_tpl ).
out->write( template_string ).
out->write( escaped_string ).
ENDMETHOD.
ENDCLASS.
Fazit
Wichtig aus Sicherheitsgründen solltest du immer die Escape Funktion verwenden und auf die Hilfsklassen und Methoden verzichten. Die Implementierung ist dabei noch einfacher als mit den Klassen und sollte leicht umsetzbar sein.
Quelle:
SAP Help - Escape