Tests de sécurité pour ABAP Cloud : Détecter et éviter les failles

Catégorie
Security
Publié
Auteur
Johannes

Les tests de sécurité sont un élément indispensable du développement ABAP Cloud. Les failles de sécurité peuvent entraîner des pertes de données, des accès non autorisés ou des violations de conformité. Cet article vous montre comment identifier et éviter les risques de sécurité en amont.

Pourquoi les tests de sécurité sont importants

Les systèmes SAP traitent souvent des données critiques pour l’entreprise et des données personnelles. Un incident de sécurité peut avoir des conséquences graves :

RisqueImpact
Fuite de donnéesDivulgation d’informations confidentielles
Accès non autoriséManipulation de données commerciales critiques
Violation de conformitéAmendes RGPD, dommages à la réputation
Panne systèmeInterruption d’activité, pertes financières

Tests de sécurité vs. tests fonctionnels

Tests fonctionnels : "L'application fonctionne-t-elle comme prévu ?"
Tests de sécurité : "L'application fonctionne-t-elle SEULEMENT comme prévu ?"

Les tests de sécurité vérifient si l’application est protégée contre les entrées malveillantes et les scénarios d’attaque.

Top 10 OWASP pour ABAP

Le Top 10 OWASP représente les risques de sécurité les plus courants dans les applications web. Beaucoup d’entre eux concernent également le développement ABAP :

Risque OWASPPertinence ABAPMesure
A01 Broken Access ControlÉlevéeRAP Authorization, AUTHORITY-CHECK
A02 Cryptographic FailuresMoyenneChiffrement sécurisé, SSL/TLS
A03 InjectionÉlevéePrévention injection SQL, validation des entrées
A04 Insecure DesignÉlevéeSecure by Design, Threat Modeling
A05 Security MisconfigurationMoyenneDestinations sécurisées, communication
A06 Vulnerable ComponentsMoyenneVérifier les dépendances, mises à jour
A07 Authentication FailuresMoyenneUtiliser l’authentification SAP
A08 Data Integrity FailuresMoyenneValidation des entrées, signature
A09 Logging FailuresMoyenneApplication Log, Audit Trail
A10 SSRFFaibleValidation URL pour les appels HTTP

Prévention des injections SQL

L’injection SQL est l’une des vulnérabilités les plus dangereuses. Dans ABAP Cloud, l’utilisation d’ABAP SQL avec liaison de variables est la meilleure protection.

Code non sécurisé (vulnérable à l’injection)

" JAMAIS AINSI ! Vulnérable à l'injection SQL
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.
" DANGEREUX : Concaténation de chaînes avec entrée utilisateur
" Un attaquant pourrait entrer : "'; DELETE FROM zcustomer; --"
DATA(lv_where) = |NAME LIKE '%{ iv_search_term }%'|.
" SQL dynamique avec entrée non validée
SELECT * FROM zcustomer
WHERE (lv_where)
INTO TABLE @rt_customers.
ENDMETHOD.
ENDCLASS.

Code sécurisé avec liaison de variables

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.
" SÉCURISÉ : Liaison de variables avec variables hôtes
" Les caractères spéciaux SQL sont automatiquement échappés
DATA(lv_pattern) = |%{ iv_search_term }%|.
SELECT * FROM zcustomer
WHERE name LIKE @lv_pattern
INTO TABLE @rt_customers.
ENDMETHOD.
ENDCLASS.

SQL dynamique sécurisé

Lorsque le SQL dynamique est inévitable, utilisez des placeholders :

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.
" Liste blanche des noms de champs autorisés
DATA(lt_allowed_fields) = VALUE string_table(
( `NAME` ) ( `CITY` ) ( `COUNTRY` )
).
" Vérifier le nom du champ par rapport à la liste blanche
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.
" Nom de champ dynamique, mais liaison de valeur sécurisée
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.

Classe helper de validation d’entrée

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.
" Autoriser uniquement lettres, chiffres et espaces
rv_valid = xsdbool(
NOT matches( val = iv_input
regex = '[^a-zA-Z0-9\s]' )
).
ENDMETHOD.
METHOD sanitize_sql_input.
" Supprimer les caractères dangereux
rv_sanitized = iv_input.
" Échapper ou supprimer les caractères spéciaux SQL
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.
" Validation simple d'email
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.
" Échapper les caractères pertinents pour HTML/XSS
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.

Prévention XSS dans Fiori

Le Cross-Site Scripting (XSS) est un risque majeur pour les applications web. Avec les apps Fiori Elements utilisant des annotations CDS, le risque est moindre, mais reste important pour les extensions personnalisées.

Sortie sécurisée dans CDS

define view entity ZI_Product
as select from zproduct
{
key product_id as ProductID,
-- Pas de contenu HTML dans les champs normaux
product_name as ProductName,
-- Si HTML nécessaire : marquer explicitement
@Semantics.text: true
description as Description
}

Extensions personnalisées sécurisées

Pour les extensions Fiori et le code UI5 personnalisé, attention :

// NON SÉCURISÉ : Insertion directe de données utilisateur
sap.ui.define([], function() {
return {
formatDescription: function(sDescription) {
// DANGEREUX : innerHTML avec données utilisateur
// var oDiv = document.createElement('div');
// oDiv.innerHTML = sDescription; // Risque XSS !
// SÉCURISÉ : Utiliser textContent
var oDiv = document.createElement('div');
oDiv.textContent = sDescription; // Sécurisé contre XSS
return oDiv;
}
};
});

Validation backend pour 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.
" Supprimer les balises script
rv_sanitized = replace( val = rv_sanitized
regex = '<script[^>]*>[\s\S]*?</script>"
with = '"
occ = 0 ).
" Supprimer les gestionnaires d'événements (onclick, onerror, etc.)
rv_sanitized = replace( val = rv_sanitized
regex = '\son\w+\s*="
with = '"
occ = 0 ).
" Supprimer les URLs JavaScript
rv_sanitized = replace( val = rv_sanitized
regex = 'javascript:"
with = '"
occ = 0 ).
" Balises autorisées : p, br, strong, em, ul, ol, li
" Supprimer toutes les autres balises (simplifié)
" En production : Utiliser une bibliothèque complète de sanitization HTML
ENDMETHOD.
ENDCLASS.

Tester les contrôles d’autorisation

Les contrôles d’autorisation doivent être testés minutieusement. Utilisez ABAP Unit avec des Test Doubles pour des tests isolés.

Test de l’autorisation d’instance

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.
" Environnement de test pour CDS Views
environment = cl_cds_test_environment=>create(
i_for_entity = 'ZI_TRAVEL"
).
ENDMETHOD.
METHOD class_teardown.
environment->destroy( ).
ENDMETHOD.
METHOD setup.
" Test-Double pour contrôle d'autorisation
" Dans les vrais tests : Utiliser cl_abap_testdouble
environment->clear_doubles( ).
ENDMETHOD.
METHOD teardown.
ROLLBACK ENTITIES.
ENDMETHOD.
METHOD test_update_auth_granted.
" GIVEN : L'utilisateur a l'autorisation de mise à jour pour l'agence 1000
" Insérer les données de test
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 : L'autorisation est vérifiée
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 : L'accès est autorisé
cl_abap_unit_assert=>assert_initial(
act = failed
msg = 'Authorization should be granted for agency 1000"
).
ENDMETHOD.
METHOD test_update_auth_denied.
" GIVEN : L'utilisateur n'a PAS d'autorisation de mise à jour pour l'agence 9999
DATA(lt_test_travels) = VALUE ztravel_tab(
( travel_uuid = cl_system_uuid=>create_uuid_x16_static( )
travel_id = '00000002"
agency_id = '9999' " Pas d'autorisation
overall_status = 'O' )
).
environment->insert_test_data( lt_test_travels ).
" WHEN : Une mise à jour est tentée
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 : L'opération est refusée
cl_abap_unit_assert=>assert_not_initial(
act = failed
msg = 'Authorization should be denied for agency 9999"
).
ENDMETHOD.
METHOD test_delete_auth_granted.
" Test pour l'autorisation de suppression
" Similaire à test_update_auth_granted
ENDMETHOD.
METHOD test_delete_auth_denied.
" Test pour autorisation de suppression manquante
" Similaire à test_update_auth_denied
ENDMETHOD.
ENDCLASS.

Mock pour 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.
" Vérifier si l'autorisation est dans la liste
rv_authorized = xsdbool(
line_exists( mt_granted_authorizations[
object = iv_object
activity = iv_activity
field_value = iv_field_value
] )
).
ENDMETHOD.
ENDCLASS.
" Utilisation dans le 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 avec autorisations spécifiques
DATA(lo_auth_mock) = NEW zcl_auth_mock(
it_granted_authorizations = VALUE #(
( object = 'ZTRAVEL"
activity = '02"
field_value = '1000' )
)
).
" Injecter le service avec le mock
DATA(lo_service) = NEW zcl_travel_service(
io_authority_checker = lo_auth_mock
).
" WHEN/THEN : Exécuter les tests
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.

Configurer les contrôles de sécurité ATC

L’ABAP Test Cockpit (ATC) propose des contrôles de sécurité spéciaux. Ceux-ci doivent être activés dans chaque projet.

Catégories de contrôles de sécurité importantes

ID contrôleDescriptionPriorité
SLIN_SECContrôles de syntaxe liés à la sécurité1
CI_DYNPRO_SECSQL dynamique et CALL FUNCTION1
CI_AUTHORITYAUTHORITY-CHECK manquant2
CI_SQL_INJRisques d’injection SQL1
CI_CODE_INJRisques d’injection de code1
CI_DIR_ACCESSAccès fichiers non sécurisés2

Créer une variante de contrôle pour la sécurité

1. Appeler la transaction ATC
2. Check Variants -> Create Check Variant
3. Nom : Z_SECURITY_CHECKS
4. Activer les contrôles suivants :
- Tous les contrôles sous "Security"
- Tous les contrôles sous "ABAP Cloud"
5. Définir le mapping de priorité :
- Security Critical : Error (Priorité 1)
- Security High : Error (Priorité 1)
- Security Medium : Warning (Priorité 2)
6. Sauvegarder la variante de contrôle

Intégrer ATC dans le pipeline

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

Contrôle ATC personnalisé pour la sécurité

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.
" Définir les attributs du contrôle
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.
" Implémenter la logique de contrôle
" Rechercher le pattern : SELECT ... WHERE (variable)
" sans validation préalable des entrées
LOOP AT io_object->get_tokens( ) ASSIGNING FIELD-SYMBOL(<token>).
" Détecter la clause WHERE dynamique
IF <token>-str CS '(' AND
<token>-type = 'W'. " Variable
" Vérifier si la variable est validée avant utilisation
" (logique simplifiée - plus complexe en production)
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.

Préparation aux tests de pénétration

Avant un test de pénétration, l’application doit être préparée minutieusement.

Créer une baseline de sécurité

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.
" Exécuter tous les contrôles de sécurité
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.
" Trier les findings par gravité
SORT rt_findings BY severity DESCENDING.
ENDMETHOD.
METHOD check_authorization_coverage.
" Vérifier que toutes les opérations RAP ont un contrôle d'autorisation
" Lire la Behavior Definition et vérifier authorization
DATA(lt_entities) = VALUE string_table(
( `ZI_TRAVEL` ) ( `ZI_BOOKING` ) ( `ZI_CUSTOMER` )
).
LOOP AT lt_entities ASSIGNING FIELD-SYMBOL(<entity>).
" Lire la Behavior Definition
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.
" Vérifier 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.
" Vérifier que tous les champs d'entrée sont validés
" Logique simplifiée
rt_findings = VALUE #( ).
ENDMETHOD.
METHOD check_sensitive_data_handling.
" Vérifier que les données sensibles (mot de passe, données bancaires) sont traitées de manière sécurisée
" Logique simplifiée
rt_findings = VALUE #( ).
ENDMETHOD.
METHOD check_logging_coverage.
" Vérifier que les actions liées à la sécurité sont journalisées
rt_findings = VALUE #( ).
ENDMETHOD.
ENDCLASS.

Scénarios de test pour les tests de pénétration

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.

Checklist de revue de sécurité

Utilisez cette checklist avant chaque mise en production ou release majeure.

Validation des entrées

  • Toutes les entrées utilisateur sont validées
  • Les paramètres SQL utilisent la liaison de variables (pas de concaténation de chaînes)
  • Les expressions régulières valident email, téléphone, etc.
  • Les téléchargements de fichiers sont vérifiés pour le type et la taille
  • Les entrées HTML sont sanitisées

Autorisation

  • RAP Authorization est configurée pour toutes les entités
  • Instance Authorization implémentée pour les données sensibles
  • Global Authorization vérifiée pour les opérations critiques
  • Tous les appels AUTHORITY-CHECK vérifient sy-subrc
  • Les fonctions admin requièrent une autorisation explicite

Protection des données

  • Les données sensibles (mots de passe, tokens) ne sont pas journalisées
  • Les données personnelles sont conformes au RGPD
  • Le chiffrement est actif pour les données sensibles
  • Communication sécurisée (HTTPS) pour tous les points de terminaison

Gestion des erreurs

  • Pas de détails techniques dans les messages d’erreur aux utilisateurs
  • Les stack traces ne sont pas envoyées au frontend
  • Les erreurs sont consignées dans l’Application Log
  • La gestion des erreurs ne révèle pas de détails système

ATC et qualité

  • Contrôles de sécurité ATC sans findings (Priorité 1)
  • Revue de code effectuée pour le code lié à la sécurité
  • Tests unitaires pour l’autorisation présents
  • Pas de failles de sécurité connues dans les dépendances

Journalisation et monitoring

  • Les événements liés à la sécurité sont journalisés
  • Les tentatives de connexion échouées sont consignées
  • Les violations d’autorisation sont signalées
  • Audit Trail actif pour les modifications de données critiques

Conclusion

Les tests de sécurité ne sont pas une action ponctuelle mais un processus continu. En intégrant les contrôles de sécurité ATC dans le pipeline CI/CD, des revues de code régulières et des tests de pénétration, vous assurez que vos applications ABAP Cloud restent sécurisées.

Les points clés à retenir :

  1. Utiliser la liaison de variables - Jamais de concaténation de chaînes pour SQL
  2. Implémenter l’autorisation - Pour chaque entité RAP
  3. Valider les entrées - Vérifier toutes les entrées utilisateur
  4. Utiliser ATC - Automatiser les contrôles de sécurité
  5. Tester régulièrement - Intégrer les tests de sécurité dans CI/CD

Articles connexes