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:
| Risiko | Auswirkung |
|---|---|
| Datenleck | Offenlegung vertraulicher Informationen |
| Unbefugter Zugriff | Manipulation kritischer Geschaeftsdaten |
| Compliance-Verstoss | DSGVO-Bussgelder, Reputationsschaden |
| Systemausfall | Betriebsunterbrechung, 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 Risiko | ABAP-Relevanz | Massnahme |
|---|---|---|
| A01 Broken Access Control | Hoch | RAP Authorization, AUTHORITY-CHECK |
| A02 Cryptographic Failures | Mittel | Sichere Verschluesselung, SSL/TLS |
| A03 Injection | Hoch | SQL Injection Prevention, Input Validation |
| A04 Insecure Design | Hoch | Secure by Design, Threat Modeling |
| A05 Security Misconfiguration | Mittel | Sichere Destinations, Kommunikation |
| A06 Vulnerable Components | Mittel | Abhaengigkeiten pruefen, Updates |
| A07 Authentication Failures | Mittel | SAP-Authentifizierung nutzen |
| A08 Data Integrity Failures | Mittel | Eingabevalidierung, Signierung |
| A09 Logging Failures | Mittel | Application Log, Audit Trail |
| A10 SSRF | Niedrig | URL-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 InjectionCLASS 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 = `<` occ = 0 ).
rv_escaped = replace( val = rv_escaped sub = `>` with = `>` occ = 0 ).
rv_escaped = replace( val = rv_escaped sub = `"` with = `"` occ = 0 ).
rv_escaped = replace( val = rv_escaped sub = `&` with = `&` 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 Benutzerdatensap.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 TestCLASS 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-ID | Beschreibung | Prioritaet |
|---|---|---|
| SLIN_SEC | Security-relevante Syntax-Pruefungen | 1 |
| CI_DYNPRO_SEC | Dynamisches SQL und CALL FUNCTION | 1 |
| CI_AUTHORITY | Fehlende AUTHORITY-CHECK | 2 |
| CI_SQL_INJ | SQL Injection Risiken | 1 |
| CI_CODE_INJ | Code Injection Risiken | 1 |
| CI_DIR_ACCESS | Unsichere Dateizugriffe | 2 |
Check Variant fuer Security erstellen
1. Transaktion ATC aufrufen2. Check Variants -> Create Check Variant3. Name: Z_SECURITY_CHECKS4. 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 speichernATC in Pipeline integrieren
# .pipeline/config.yml fuer SAP Piperstages: - 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:
- Variablenbindung verwenden - Niemals String-Konkatenation fuer SQL
- Authorization implementieren - Fuer jede RAP-Entitaet
- Input validieren - Alle Benutzereingaben pruefen
- ATC nutzen - Security Checks automatisieren
- Regelmaessig testen - Security Tests in CI/CD integrieren