Security Testing fuer ABAP Cloud: Sicherheitsluecken erkennen und vermeiden

kategorie
Security
Veröffentlicht
autor
Johannes

Security Testing ist ein unverzichtbarer Bestandteil der ABAP Cloud Entwicklung. Sicherheitsluecken koennen zu Datenverlust, unbefugtem Zugriff oder Compliance-Verstoessen fuehren. Dieser Artikel zeigt dir, wie du Sicherheitsrisiken fruehzeitig erkennst und vermeidest.

Warum Security Testing wichtig ist

SAP-Systeme verarbeiten haeufig geschaeftskritische und personenbezogene Daten. Ein Sicherheitsvorfall kann schwerwiegende Folgen haben:

RisikoAuswirkung
DatenleckOffenlegung vertraulicher Informationen
Unbefugter ZugriffManipulation kritischer Geschaeftsdaten
Compliance-VerstossDSGVO-Bussgelder, Reputationsschaden
SystemausfallBetriebsunterbrechung, finanzielle Verluste

Security Testing vs. funktionale Tests

Funktionale Tests: "Funktioniert die Anwendung wie erwartet?"
Security Tests: "Funktioniert die Anwendung NUR wie erwartet?"

Security Testing prueft, ob die Anwendung gegen boesartige Eingaben und Angriffsszenarien geschuetzt ist.

OWASP Top 10 fuer ABAP

Die OWASP Top 10 sind die haeufigsten Sicherheitsrisiken in Webanwendungen. Viele davon betreffen auch ABAP-Entwicklung:

OWASP RisikoABAP-RelevanzMassnahme
A01 Broken Access ControlHochRAP Authorization, AUTHORITY-CHECK
A02 Cryptographic FailuresMittelSichere Verschluesselung, SSL/TLS
A03 InjectionHochSQL Injection Prevention, Input Validation
A04 Insecure DesignHochSecure by Design, Threat Modeling
A05 Security MisconfigurationMittelSichere Destinations, Kommunikation
A06 Vulnerable ComponentsMittelAbhaengigkeiten pruefen, Updates
A07 Authentication FailuresMittelSAP-Authentifizierung nutzen
A08 Data Integrity FailuresMittelEingabevalidierung, Signierung
A09 Logging FailuresMittelApplication Log, Audit Trail
A10 SSRFNiedrigURL-Validierung bei HTTP-Calls

SQL Injection Prevention

SQL Injection ist eine der gefaehrlichsten Schwachstellen. In ABAP Cloud ist die Verwendung von ABAP SQL mit Variablenbindung der beste Schutz.

Unsicherer Code (anfaellig fuer Injection)

" NIEMALS SO! Anfaellig fuer SQL Injection
CLASS zcl_insecure_query DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS search_customers
IMPORTING
iv_search_term TYPE string
RETURNING
VALUE(rt_customers) TYPE TABLE OF zcustomer.
ENDCLASS.
CLASS zcl_insecure_query IMPLEMENTATION.
METHOD search_customers.
" GEFAEHRLICH: String-Konkatenation mit Benutzereingabe
" Ein Angreifer koennte eingeben: "'; DELETE FROM zcustomer; --"
DATA(lv_where) = |NAME LIKE '%{ iv_search_term }%'|.
" Dynamisches SQL mit unvalidierter Eingabe
SELECT * FROM zcustomer
WHERE (lv_where)
INTO TABLE @rt_customers.
ENDMETHOD.
ENDCLASS.

Sicherer Code mit Variablenbindung

CLASS zcl_secure_query DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS search_customers
IMPORTING
iv_search_term TYPE string
RETURNING
VALUE(rt_customers) TYPE TABLE OF zcustomer.
ENDCLASS.
CLASS zcl_secure_query IMPLEMENTATION.
METHOD search_customers.
" SICHER: Variablenbindung mit Host-Variablen
" SQL-Sonderzeichen werden automatisch escaped
DATA(lv_pattern) = |%{ iv_search_term }%|.
SELECT * FROM zcustomer
WHERE name LIKE @lv_pattern
INTO TABLE @rt_customers.
ENDMETHOD.
ENDCLASS.

Sicheres dynamisches SQL

Wenn dynamisches SQL unvermeidbar ist, nutze Platzhalter:

CLASS zcl_dynamic_secure DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS search_with_filter
IMPORTING
iv_field_name TYPE string
iv_search_value TYPE string
RETURNING
VALUE(rt_result) TYPE TABLE OF zcustomer.
ENDCLASS.
CLASS zcl_dynamic_secure IMPLEMENTATION.
METHOD search_with_filter.
" Whitelist fuer erlaubte Feldnamen
DATA(lt_allowed_fields) = VALUE string_table(
( `NAME` ) ( `CITY` ) ( `COUNTRY` )
).
" Feldname gegen Whitelist pruefen
IF NOT line_exists( lt_allowed_fields[ table_line = to_upper( iv_field_name ) ] ).
RAISE EXCEPTION TYPE zcx_invalid_field
EXPORTING
textid = zcx_invalid_field=>field_not_allowed
field_name = iv_field_name.
ENDIF.
" Dynamischer Feldname, aber sichere Wertbindung
DATA(lv_where) = |{ to_upper( iv_field_name ) } LIKE @LV_PATTERN|.
DATA(lv_pattern) = |%{ iv_search_value }%|.
SELECT * FROM zcustomer
WHERE (lv_where)
INTO TABLE @rt_result.
ENDMETHOD.
ENDCLASS.

Input Validation Helper Klasse

CLASS zcl_input_validator DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS validate_alphanumeric
IMPORTING
iv_input TYPE string
RETURNING
VALUE(rv_valid) TYPE abap_bool.
CLASS-METHODS sanitize_sql_input
IMPORTING
iv_input TYPE string
RETURNING
VALUE(rv_sanitized) TYPE string.
CLASS-METHODS validate_email
IMPORTING
iv_email TYPE string
RETURNING
VALUE(rv_valid) TYPE abap_bool.
CLASS-METHODS escape_special_chars
IMPORTING
iv_input TYPE string
RETURNING
VALUE(rv_escaped) TYPE string.
ENDCLASS.
CLASS zcl_input_validator IMPLEMENTATION.
METHOD validate_alphanumeric.
" Nur Buchstaben, Zahlen und Leerzeichen erlauben
rv_valid = xsdbool(
NOT matches( val = iv_input
regex = '[^a-zA-Z0-9\s]' )
).
ENDMETHOD.
METHOD sanitize_sql_input.
" Gefaehrliche Zeichen entfernen
rv_sanitized = iv_input.
" SQL-Sonderzeichen escapen oder entfernen
rv_sanitized = replace( val = rv_sanitized
sub = `'`
with = `''`
occ = 0 ).
rv_sanitized = replace( val = rv_sanitized
sub = `--`
with = ``
occ = 0 ).
rv_sanitized = replace( val = rv_sanitized
sub = `;`
with = ``
occ = 0 ).
ENDMETHOD.
METHOD validate_email.
" Einfache E-Mail-Validierung
rv_valid = xsdbool(
matches( val = iv_email
regex = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' )
).
ENDMETHOD.
METHOD escape_special_chars.
rv_escaped = iv_input.
" HTML/XSS-relevante Zeichen escapen
rv_escaped = replace( val = rv_escaped
sub = `<`
with = `&lt;`
occ = 0 ).
rv_escaped = replace( val = rv_escaped
sub = `>`
with = `&gt;`
occ = 0 ).
rv_escaped = replace( val = rv_escaped
sub = `"`
with = `&quot;`
occ = 0 ).
rv_escaped = replace( val = rv_escaped
sub = `&`
with = `&amp;`
occ = 0 ).
ENDMETHOD.
ENDCLASS.

XSS Prevention in Fiori

Cross-Site Scripting (XSS) ist bei Webanwendungen ein grosses Risiko. Bei Fiori Elements Apps mit CDS-Annotationen ist das Risiko geringer, aber bei Custom Extensions wichtig.

Sichere Ausgabe in CDS

define view entity ZI_Product
as select from zproduct
{
key product_id as ProductID,
-- Keine HTML-Inhalte in regulaeren Feldern
product_name as ProductName,
-- Falls HTML benoetigt: explizit markieren
@Semantics.text: true
description as Description
}

Sichere Custom Extensions

Bei Fiori Extensions und Custom UI5 Code beachten:

// UNSICHER: Direktes Einfuegen von Benutzerdaten
sap.ui.define([], function() {
return {
formatDescription: function(sDescription) {
// GEFAEHRLICH: innerHTML mit Benutzerdaten
// var oDiv = document.createElement('div');
// oDiv.innerHTML = sDescription; // XSS-Risiko!
// SICHER: textContent verwenden
var oDiv = document.createElement('div');
oDiv.textContent = sDescription; // XSS-sicher
return oDiv;
}
};
});

Backend-Validierung fuer Rich Text

CLASS zcl_html_sanitizer DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS sanitize_html
IMPORTING
iv_html TYPE string
RETURNING
VALUE(rv_sanitized) TYPE string.
ENDCLASS.
CLASS zcl_html_sanitizer IMPLEMENTATION.
METHOD sanitize_html.
rv_sanitized = iv_html.
" Script-Tags entfernen
rv_sanitized = replace( val = rv_sanitized
regex = '<script[^>]*>[\s\S]*?</script>'
with = ''
occ = 0 ).
" Event-Handler entfernen (onclick, onerror, etc.)
rv_sanitized = replace( val = rv_sanitized
regex = '\son\w+\s*='
with = ''
occ = 0 ).
" JavaScript-URLs entfernen
rv_sanitized = replace( val = rv_sanitized
regex = 'javascript:'
with = ''
occ = 0 ).
" Erlaubte Tags: p, br, strong, em, ul, ol, li
" Alle anderen Tags entfernen (vereinfacht)
" In Produktion: Vollstaendige HTML-Sanitizer-Library verwenden
ENDMETHOD.
ENDCLASS.

Authorization Checks testen

Berechtigungspruefungen muessen gruendlich getestet werden. Nutze ABAP Unit mit Test Doubles fuer isolierte Tests.

Test der Instance Authorization

CLASS ltcl_travel_authorization DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA:
environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS:
class_setup,
class_teardown.
METHODS:
setup,
teardown.
METHODS:
test_update_auth_granted FOR TESTING,
test_update_auth_denied FOR TESTING,
test_delete_auth_granted FOR TESTING,
test_delete_auth_denied FOR TESTING.
ENDCLASS.
CLASS ltcl_travel_authorization IMPLEMENTATION.
METHOD class_setup.
" Test-Umgebung fuer CDS Views
environment = cl_cds_test_environment=>create(
i_for_entity = 'ZI_TRAVEL'
).
ENDMETHOD.
METHOD class_teardown.
environment->destroy( ).
ENDMETHOD.
METHOD setup.
" Test-Double fuer Berechtigungspruefung
" In echten Tests: cl_abap_testdouble verwenden
environment->clear_doubles( ).
ENDMETHOD.
METHOD teardown.
ROLLBACK ENTITIES.
ENDMETHOD.
METHOD test_update_auth_granted.
" GIVEN: Benutzer hat Update-Berechtigung fuer Agency 1000
" Test-Daten einfuegen
DATA(lt_test_travels) = VALUE ztravel_tab(
( travel_uuid = cl_system_uuid=>create_uuid_x16_static( )
travel_id = '00000001'
agency_id = '1000'
overall_status = 'O' )
).
environment->insert_test_data( lt_test_travels ).
" WHEN: Authorization wird geprueft
READ ENTITIES OF zi_travel
ENTITY Travel
ALL FIELDS WITH VALUE #(
( %key-TravelUUID = lt_test_travels[ 1 ]-travel_uuid )
)
RESULT DATA(lt_result)
FAILED DATA(failed).
" THEN: Zugriff ist erlaubt
cl_abap_unit_assert=>assert_initial(
act = failed
msg = 'Authorization should be granted for agency 1000'
).
ENDMETHOD.
METHOD test_update_auth_denied.
" GIVEN: Benutzer hat KEINE Update-Berechtigung fuer Agency 9999
DATA(lt_test_travels) = VALUE ztravel_tab(
( travel_uuid = cl_system_uuid=>create_uuid_x16_static( )
travel_id = '00000002'
agency_id = '9999' " Keine Berechtigung
overall_status = 'O' )
).
environment->insert_test_data( lt_test_travels ).
" WHEN: Update versucht wird
MODIFY ENTITIES OF zi_travel
ENTITY Travel
UPDATE FIELDS ( AgencyID )
WITH VALUE #(
( %key-TravelUUID = lt_test_travels[ 1 ]-travel_uuid
AgencyID = '8888' )
)
FAILED DATA(failed)
REPORTED DATA(reported).
" THEN: Operation wird abgelehnt
cl_abap_unit_assert=>assert_not_initial(
act = failed
msg = 'Authorization should be denied for agency 9999'
).
ENDMETHOD.
METHOD test_delete_auth_granted.
" Test fuer Delete-Berechtigung
" Aehnlich zu test_update_auth_granted
ENDMETHOD.
METHOD test_delete_auth_denied.
" Test fuer fehlende Delete-Berechtigung
" Aehnlich zu test_update_auth_denied
ENDMETHOD.
ENDCLASS.

Mock fuer Authority-Check

CLASS zcl_auth_mock DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES zif_authority_checker.
METHODS constructor
IMPORTING
it_granted_authorizations TYPE ztt_auth_grants.
PRIVATE SECTION.
DATA mt_granted_authorizations TYPE ztt_auth_grants.
ENDCLASS.
CLASS zcl_auth_mock IMPLEMENTATION.
METHOD constructor.
mt_granted_authorizations = it_granted_authorizations.
ENDMETHOD.
METHOD zif_authority_checker~check_authority.
" Pruefe ob Berechtigung in der Liste ist
rv_authorized = xsdbool(
line_exists( mt_granted_authorizations[
object = iv_object
activity = iv_activity
field_value = iv_field_value
] )
).
ENDMETHOD.
ENDCLASS.
" Verwendung im Test
CLASS ltcl_with_auth_mock DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS test_with_mock_authorization FOR TESTING.
ENDCLASS.
CLASS ltcl_with_auth_mock IMPLEMENTATION.
METHOD test_with_mock_authorization.
" GIVEN: Mock mit spezifischen Berechtigungen
DATA(lo_auth_mock) = NEW zcl_auth_mock(
it_granted_authorizations = VALUE #(
( object = 'ZTRAVEL'
activity = '02'
field_value = '1000' )
)
).
" Service mit Mock injizieren
DATA(lo_service) = NEW zcl_travel_service(
io_authority_checker = lo_auth_mock
).
" WHEN/THEN: Tests ausfuehren
cl_abap_unit_assert=>assert_true(
act = lo_service->can_update_travel( iv_agency_id = '1000' )
).
cl_abap_unit_assert=>assert_false(
act = lo_service->can_update_travel( iv_agency_id = '2000' )
).
ENDMETHOD.
ENDCLASS.

ATC Security Checks konfigurieren

Das ABAP Test Cockpit (ATC) bietet spezielle Security-Checks. Diese sollten in jedem Projekt aktiviert sein.

Wichtige Security Check-Kategorien

Check-IDBeschreibungPrioritaet
SLIN_SECSecurity-relevante Syntax-Pruefungen1
CI_DYNPRO_SECDynamisches SQL und CALL FUNCTION1
CI_AUTHORITYFehlende AUTHORITY-CHECK2
CI_SQL_INJSQL Injection Risiken1
CI_CODE_INJCode Injection Risiken1
CI_DIR_ACCESSUnsichere Dateizugriffe2

Check Variant fuer Security erstellen

1. Transaktion ATC aufrufen
2. Check Variants -> Create Check Variant
3. Name: Z_SECURITY_CHECKS
4. Folgende Checks aktivieren:
- Alle Checks unter "Security"
- Alle Checks unter "ABAP Cloud"
5. Priority Mapping festlegen:
- Security Critical: Error (Priority 1)
- Security High: Error (Priority 1)
- Security Medium: Warning (Priority 2)
6. Check Variant speichern

ATC in Pipeline integrieren

# .pipeline/config.yml fuer SAP Piper
stages:
- name: "ABAP Environment"
steps:
- name: "ATC Check"
config:
atcCheck:
atcConfig:
checkVariant: "Z_SECURITY_CHECKS"
failOnSeverity: "error"
objectSet:
packages:
- "ZTRAVEL_APP"

Custom ATC Check fuer Security

CLASS zcl_atc_security_check DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_ci_atc_check.
CONSTANTS:
c_check_id TYPE if_ci_atc_check=>ty_s_check_id VALUE 'ZSEC01'.
ENDCLASS.
CLASS zcl_atc_security_check IMPLEMENTATION.
METHOD if_ci_atc_check~get_attributes.
" Check-Attribute definieren
result = VALUE #(
check_id = c_check_id
shorttext = 'Security: Unvalidated input in SQL'
category = 'CL_CI_CATEGORY_SECURITY'
default_variant = ''
).
ENDMETHOD.
METHOD if_ci_atc_check~run.
" Check-Logik implementieren
" Suche nach Pattern: SELECT ... WHERE (variable)
" ohne vorherige Input-Validierung
LOOP AT io_object->get_tokens( ) ASSIGNING FIELD-SYMBOL(<token>).
" Dynamische WHERE-Klausel erkennen
IF <token>-str CS '(' AND
<token>-type = 'W'. " Variable
" Pruefe ob Variable vor Verwendung validiert wird
" (vereinfachte Logik - in Produktion komplexer)
DATA(ls_finding) = VALUE if_ci_atc_check=>ty_s_finding(
code = 'ZSEC01_DYN_SQL'
category = 'CL_CI_CATEGORY_SECURITY'
priority = if_ci_atc_check=>c_prio_error
message = |Dynamic SQL with variable { <token>-str } - validate input|
position = <token>-row
).
APPEND ls_finding TO rt_findings.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Penetration Testing Vorbereitung

Vor einem Penetration Test sollte die Anwendung gruendlich vorbereitet werden.

Security Baseline erstellen

CLASS zcl_security_baseline DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS run_security_assessment
RETURNING
VALUE(rt_findings) TYPE ztt_security_findings.
PRIVATE SECTION.
METHODS check_authorization_coverage
RETURNING
VALUE(rt_findings) TYPE ztt_security_findings.
METHODS check_input_validation
RETURNING
VALUE(rt_findings) TYPE ztt_security_findings.
METHODS check_sensitive_data_handling
RETURNING
VALUE(rt_findings) TYPE ztt_security_findings.
METHODS check_logging_coverage
RETURNING
VALUE(rt_findings) TYPE ztt_security_findings.
ENDCLASS.
CLASS zcl_security_baseline IMPLEMENTATION.
METHOD run_security_assessment.
" Alle Security-Checks ausfuehren
APPEND LINES OF check_authorization_coverage( ) TO rt_findings.
APPEND LINES OF check_input_validation( ) TO rt_findings.
APPEND LINES OF check_sensitive_data_handling( ) TO rt_findings.
APPEND LINES OF check_logging_coverage( ) TO rt_findings.
" Findings sortieren nach Schweregrad
SORT rt_findings BY severity DESCENDING.
ENDMETHOD.
METHOD check_authorization_coverage.
" Pruefe ob alle RAP-Operationen Berechtigungspruefung haben
" Lese Behavior Definition und pruefe auf authorization
DATA(lt_entities) = VALUE string_table(
( `ZI_TRAVEL` ) ( `ZI_BOOKING` ) ( `ZI_CUSTOMER` )
).
LOOP AT lt_entities ASSIGNING FIELD-SYMBOL(<entity>).
" Behavior Definition lesen
SELECT SINGLE * FROM r_behavdef
WHERE object_name = @<entity>
INTO @DATA(ls_behavior).
IF sy-subrc <> 0.
APPEND VALUE #(
category = 'AUTHORIZATION'
severity = 'HIGH'
entity = <entity>
message = |No behavior definition found for { <entity> }|
) TO rt_findings.
CONTINUE.
ENDIF.
" Pruefe auf authorization master/dependent
IF ls_behavior-source NS 'authorization'.
APPEND VALUE #(
category = 'AUTHORIZATION'
severity = 'CRITICAL'
entity = <entity>
message = |No authorization defined for { <entity> }|
) TO rt_findings.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD check_input_validation.
" Pruefe ob alle Eingabefelder validiert werden
" Vereinfachte Logik
rt_findings = VALUE #( ).
ENDMETHOD.
METHOD check_sensitive_data_handling.
" Pruefe ob sensible Daten (Passwort, Bankdaten) sicher behandelt werden
" Vereinfachte Logik
rt_findings = VALUE #( ).
ENDMETHOD.
METHOD check_logging_coverage.
" Pruefe ob sicherheitsrelevante Aktionen geloggt werden
rt_findings = VALUE #( ).
ENDMETHOD.
ENDCLASS.

Test-Szenarien fuer Penetration Test

CLASS zcl_pentest_scenarios DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_test_case,
name TYPE string,
category TYPE string,
description TYPE string,
test_input TYPE string,
expected TYPE string,
END OF ty_test_case,
tt_test_cases TYPE TABLE OF ty_test_case WITH EMPTY KEY.
METHODS get_sql_injection_tests
RETURNING
VALUE(rt_tests) TYPE tt_test_cases.
METHODS get_xss_tests
RETURNING
VALUE(rt_tests) TYPE tt_test_cases.
METHODS get_authorization_bypass_tests
RETURNING
VALUE(rt_tests) TYPE tt_test_cases.
ENDCLASS.
CLASS zcl_pentest_scenarios IMPLEMENTATION.
METHOD get_sql_injection_tests.
rt_tests = VALUE #(
( name = 'SQL_INJ_01'
category = 'SQL Injection'
description = 'Simple quote injection'
test_input = |''; DROP TABLE ztravel; --|
expected = 'Rejection or escaped output' )
( name = 'SQL_INJ_02'
category = 'SQL Injection'
description = 'Union-based injection'
test_input = |' UNION SELECT * FROM usr02 --|
expected = 'Rejection or escaped output' )
( name = 'SQL_INJ_03'
category = 'SQL Injection'
description = 'Boolean-based blind injection'
test_input = |' OR '1'='1|
expected = 'Same result as normal query' )
( name = 'SQL_INJ_04'
category = 'SQL Injection'
description = 'Time-based blind injection'
test_input = |'; WAITFOR DELAY '00:00:10' --|
expected = 'No delay in response' )
).
ENDMETHOD.
METHOD get_xss_tests.
rt_tests = VALUE #(
( name = 'XSS_01'
category = 'Cross-Site Scripting'
description = 'Simple script tag'
test_input = |<script>alert('XSS')</script>|
expected = 'Escaped or sanitized output' )
( name = 'XSS_02'
category = 'Cross-Site Scripting'
description = 'Event handler injection'
test_input = |<img src=x onerror=alert('XSS')>|
expected = 'Event handler removed' )
( name = 'XSS_03'
category = 'Cross-Site Scripting'
description = 'JavaScript URL'
test_input = |<a href="javascript:alert('XSS')">Click</a>|
expected = 'Link sanitized or removed' )
).
ENDMETHOD.
METHOD get_authorization_bypass_tests.
rt_tests = VALUE #(
( name = 'AUTH_01'
category = 'Authorization Bypass'
description = 'Access other users data via ID manipulation'
test_input = 'Change TravelUUID in request to another users travel'
expected = 'Access denied or no data returned' )
( name = 'AUTH_02'
category = 'Authorization Bypass'
description = 'Horizontal privilege escalation'
test_input = 'Attempt to modify travel of different agency'
expected = 'Authorization error returned' )
( name = 'AUTH_03'
category = 'Authorization Bypass'
description = 'Vertical privilege escalation'
test_input = 'Attempt admin action without admin role'
expected = 'Authorization error returned' )
).
ENDMETHOD.
ENDCLASS.

Security Review Checkliste

Verwende diese Checkliste vor jedem Go-Live oder Major Release.

Input Validation

  • Alle Benutzereingaben werden validiert
  • SQL-Parameter nutzen Variablenbindung (keine String-Konkatenation)
  • Regulaere Ausdruecke validieren E-Mail, Telefon, etc.
  • Dateiuploads werden auf Typ und Groesse geprueft
  • HTML-Eingaben werden sanitisiert

Authorization

  • RAP Authorization ist fuer alle Entitaeten konfiguriert
  • Instance Authorization fuer sensible Daten implementiert
  • Global Authorization fuer kritische Operationen geprueft
  • Alle AUTHORITY-CHECK Aufrufe pruefen sy-subrc
  • Admin-Funktionen erfordern explizite Berechtigung

Data Protection

  • Sensible Daten (Passwoerter, Token) werden nicht geloggt
  • Personenbezogene Daten sind DSGVO-konform
  • Verschluesselung fuer sensible Daten aktiv
  • Secure Communication (HTTPS) fuer alle Endpunkte

Error Handling

  • Keine technischen Details in Fehlermeldungen an Benutzer
  • Stack Traces werden nicht an Frontend gesendet
  • Fehler werden in Application Log protokolliert
  • Fehlerbehandlung verraet keine Systemdetails

ATC und Qualitaet

  • ATC Security Checks ohne Findings (Priority 1)
  • Code Review fuer sicherheitsrelevanten Code durchgefuehrt
  • Unit Tests fuer Authorization vorhanden
  • Keine bekannten Sicherheitsluecken in Abhaengigkeiten

Logging und Monitoring

  • Security-relevante Ereignisse werden geloggt
  • Failed Login Attempts werden protokolliert
  • Berechtigungsverletzungen werden gemeldet
  • Audit Trail fuer kritische Datenaenderungen aktiv

Fazit

Security Testing ist keine einmalige Aktion, sondern ein kontinuierlicher Prozess. Durch die Integration von ATC Security Checks in die CI/CD Pipeline, regelmaessige Code Reviews und Penetration Tests stellst du sicher, dass deine ABAP Cloud Anwendungen sicher bleiben.

Die wichtigsten Takeaways:

  1. Variablenbindung verwenden - Niemals String-Konkatenation fuer SQL
  2. Authorization implementieren - Fuer jede RAP-Entitaet
  3. Input validieren - Alle Benutzereingaben pruefen
  4. ATC nutzen - Security Checks automatisieren
  5. Regelmaessig testen - Security Tests in CI/CD integrieren

Weiterführende Artikel