E6: IT services cybersecurity

Denas - SLAM, December 2022 session

Methodology and annotated worked solution: E6: IT services cybersecurity, BTS SIO.

  • Duration 4h
  • Pathway SLAM
  • Session December 2022

Lockbay annotated solution

Official exam paper

Denas case study - 2022 session, U6/E6 (SLAM), duration 4h, coeff. 4, out of 80 marks (4 parts: 12 + 26 + 24 + 18 pts). Paper code 22SI5SLAM-NC. 📄 Download the official Denas exam paper (réseaucerta.org)

Lockbay does not host the exam paper: this model answer is an original Lockbay production answering the questions from the official paper. Exam paper © Éducation nationale.

The Denas case study (aeronautical electronics) focuses on the PartEdge web application: spare parts requests sent to the ERP via a REST API. Four parts: risk analysis, authentication (hashing, anti-injection, 2FA), request validation (signature, trigger, modelling) and REST API. Question-by-question solutions.

Part A - Participation in the risk analysis workshop 12 pts
A1.1

Security criteria (DICP) for use cases 2 and 6

We evaluate the four criteria: Confidentiality, Integrity, Availability, Proof (0 / + / ++).

CaseConfidentialityIntegrityAvailabilityProof
2 - View catalogue+++++0
6 - Sign electronically+++++++

Justification: for case 2, the catalogue (prices, stock levels) is commercially sensitive, but above all it must be accurate (integrity ++) and available 24/7 (++); no proof is required for simple viewing. For case 6, the signature legally binds the customer: proof is paramount (++), as are the confidentiality and integrity of contractual documents.

A2.1

Business impact of dreaded events nos. 4 and 5

  • ER no. 4 (customer confirms requests for parts incompatible with the aircraft): undue immobilisation of parts removed from stock for an unusable request, stock shortages for genuine needs, aircraft grounded at other customers (up to €25,000/day), and loss of revenue and reputation → severity ++.
  • ER no. 5 (attacker accesses ERP data via the request interface): compromise of the core IS (orders, stock, invoicing, customers), leak or alteration of contractual and financial data, falsified aeronautical traceability jeopardising aircraft safety → severity ++.
A2.2

Two measures for risk scenarios nos. 2 and 5

  • Scenario 2 (password attack / brute force tool):
    1. Hash passwords with salting (Bcrypt) - a database breach does not reveal plain-text passwords;
    2. Limit attempts (lockout/delay after N failed attempts) and enforce a strong password policy + 2FA (OTP).
  • Scenario 5 (ERP corruption via code injection in requests):
    1. Validate and type all data received by the REST API (whitelists, regular expressions) before transmission to the ERP system;
    2. Isolate the API in a DMZ with a least-privilege service account on the ERP side and parameterised queries on the database side.
A2.3

Motivations for scenarios nos. 3 and 4

Both scenarios fall under competitive cyber-influence: an unscrupulous customer reserves parts they will not confirm (scenario 3) or requests incompatible parts (scenario 4) to deplete available stock. As stock levels are very low (pandemic, extended supplier lead times), the aim is to deprive competitors of the parts they need and ground their aircraft (with losses of up to €25,000/day), thereby gaining an unfair commercial advantage.

Part B - Improving authentication 26 pts
B1.1

Encryption (AES) or hashing (SHA) for passwords?

Hashing is the most secure solution. Symmetric encryption (AES) is reversible: the decryption key must be stored somewhere; if it is stolen with the database, all passwords can be recovered in plain text. Hashing is one-way (irreversible): passwords are never stored, only hashes are compared. Furthermore, the application never needs to retrieve a password, only verify it - hashing is sufficient.

B1.2

Importance of salting (salt) with Bcrypt

The salt is a random, unique value per user, added to the password before hashing. It ensures that two customers with the same password obtain different hashes, which:

  • renders precomputed tables (rainbow tables) useless;
  • prevents identifying identical passwords across accounts;
  • forces the attacker to crack each hash individually.

Bcrypt automatically generates and incorporates the salt into the resulting hash, and applies a cost factor (deliberate slowness) that significantly slows down brute-force attacks.

B2.1

Securing readByLogin (ClientDao) against SQL injection

The original code (Document B4) concatenates $login into the query (line 6) - a direct injection vulnerability. It is replaced with a prepared statement with a bound parameter.

// Ligne 6 — modifiée : on remplace la valeur concaténée par un marqueur ?
$req = "SELECT id, nom, login, pass, courriel, telephone, adresse,
        pays, estBloque, codePinOtp FROM client WHERE login = ?";

// Lignes 6bis/7 — insérées : préparation, liaison de la valeur, exécution
$prep = $connex->prepare($req);
$prep->bindValue(1, $login, PDO::PARAM_STR);
$prep->execute();

// Ligne 8 — modifiée : on lit le résultat sur l'objet préparé
$enreg = $prep->fetch(PDO::FETCH_OBJ);

// Ligne 16 — modifiée : fermeture du curseur de la requête préparée
$prep->closeCursor();

The input value is never interpreted as SQL code: it is sent separately from the query. The concatenation '" . $login . "' is removed.

B3.1

Two other 2FA solutions

In addition to a physical OTP key:

  1. OTP via an authenticator app (TOTP such as Google Authenticator / FreeOTP) or via SMS / email sent to a trusted channel;
  2. Biometric authentication (fingerprint, facial recognition) or a FIDO2/U2F hardware key (such as a YubiKey) plugged into the workstation.
B3.2

Adding the OTP field to loginView.php

An input field for the 6-digit code is inserted between the password and the button (after line 3):

<!-- Ligne 3bis — insérée -->
<label for="otp">Code OTP :</label>
<input type="text" id="otp" name="otp" maxlength="6" pattern="[0-9]{6}" required/>
B3.3

OTP verification and logging in verifLogin (LoginCtrl)

The entered OTP code is retrieved, compared with the one generated by the OTP class, and each attempt is logged via syslog() in the required format (Documents B1 and B6). Insertions into verifLogin:

// Ligne 10bis — insérée : récupération du code OTP saisi
$otpForm = filter_input(INPUT_POST, 'otp', FILTER_SANITIZE_NUMBER_INT);

// Lignes 19 à 24 — remplacées : mot de passe OK -> on contrôle l'OTP, puis on journalise
if (password_verify($passForm, $client->getPass())) {
    $unOtp  = new OTP($client);
    $codeOk = $unOtp->getCode(new DateTime());
    if ($otpForm == $codeOk) {
        // Connexion réussie : on journalise puis on affiche l'accueil
        syslog(LOG_INFO, "Connexion client " . $client->getId());
        new AccueilView();
    } else {
        // Mot de passe valide mais OTP erroné
        syslog(LOG_WARNING, "Erreur connexion client " . $loginForm . ", cause : Erreur OTP");
        $erreur = true;
    }
} else {
    // Couple login / mot de passe invalide
    syslog(LOG_WARNING, "Erreur connexion client " . $loginForm . ", cause : Erreur login/mot de passe");
    $erreur = true;
}

The $client == null case (unknown login, line 14) must also log a LOG_WARNING with the reason Erreur login/mot de passe. It ends with closelog();.

Part C - Validating customer requests 24 pts
C1.1

Condition for the admissibility of electronic exchanges in court

An electronic exchange has the same probative value as a paper document, provided that the author of the document can be reliably identified and the integrity of the content guaranteed (unaltered document), via an electronic signature based on a reliable process (certificate issued by a qualified trust service provider, in accordance with the eIDAS regulation and the Civil Code).

C1.2

Technical solutions for the four requirements

Legal department requirementTechnical solution
1. Confidentiality of exchangesDocument encryption (TLS communication encryption and/or encryption of the document with the recipient's public key)
2. Authenticity + non-modificationElectronic signature: document hash signed with the sender's private key; any modification invalidates the signature
3. Proof of receipt by the customerAcknowledgement of receipt (electronic registered delivery / qualified timestamping), ideally countersigned by the recipient
4. Legal commitment of the customerCustomer electronic signature based on a qualified certificate (eIDAS), which legally binds them
C2.1

Query: customers with unconfirmed requests older than 24 h

A request is abusive if it is not confirmed (dateConfirmation IS NULL) more than 24 h after its creation. We display id, nom, and the total number of parts requested.

SELECT c.id, c.nom, COUNT(d.id) AS nbPieces
FROM Client c
JOIN Demande d ON d.idClient = c.id
WHERE d.dateConfirmation IS NULL
  AND d.dateDemande < NOW() - INTERVAL 24 HOUR
GROUP BY c.id, c.nom;
C2.2

Trigger to block abusive customers

Before inserting a request, nb_abus(idClient) is called. If the customer reaches 2 violations, they are blocked (estBloque = true) and request creation is prevented (raising an error).

CREATE OR REPLACE TRIGGER verif_client_abus
BEFORE INSERT ON Demande
FOR EACH ROW
BEGIN
    DECLARE nb INT;
    SET nb = nb_abus(NEW.idClient);
    IF nb >= 2 THEN
        UPDATE Client SET estBloque = TRUE WHERE id = NEW.idClient;
        -- on empêche l'enregistrement de la nouvelle demande
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'Client bloqué pour demandes abusives';
    END IF;
END;
C2.3

Modelling part type / aircraft model compatibility

A part type can fit several aircraft models, and a model accepts several part types: a many-to-many relationship, with a comment attached to each compatibility. We add an entity ModeleAeronef and an association table Compatibilite:

Schéma relationnel ajouté :
  ModeleAeronef(id, libelle)
  Compatibilite(idTypePiece, idModele, commentaire)
        clé primaire : (idTypePiece, idModele)
        clés étrangères : idTypePiece -> TypePiece(id)
                          idModele    -> ModeleAeronef(id)

In a class diagram: association *..* between TypePiece and ModeleAeronef, reified by an association class Compatibilite carrying the commentaire attribute.

C2.4

Implementing the business constraint (without coding it)

When entering a request, check that the (requested part type, relevant aircraft model) pair exists in the Compatibilite table. This constraint can be implemented using a trigger BEFORE INSERT on Demande that rejects the request if no matching compatibility row is found (and/or via an application check on the service side before calling the database).

Part D - Sending data to the ERP / REST API 18 pts
D1.1

REST method createDemande (POST) in DemandeRest

We call DemandeService.create(); on success we return 201 CREATED, otherwise 400 BAD_REQUEST (the request could not be completed).

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createDemande(DemandeJson laDemandeJson) {
    boolean ret = DemandeService.create(laDemandeJson);
    if (ret == true) {
        return Response.status(Status.CREATED).build();
    } else {
        return Response.status(Status.BAD_REQUEST).build();
    }
}
D2.1

Checks in verifDonneesCreate (regex) + additional check

a) The provided code contains incorrect regexes: ^[0-9]4-[0-9]2-[0-9]2$ does not express repetition (it should be {4}, {2}, {2}) and INTERNE|EXTERNE is not anchored (it would accept XINTERNEY). We fix this and add the exchange type check:

// Date au format ISO YYYY-MM-DD (corrigé avec les quantificateurs {n})
if (Pattern.matches("^[0-9]{4}-[0-9]{2}-[0-9]{2}$", laDem.getDateDemande()) == false) {
    res = false;
}
// Mode de transport : INTERNE ou EXTERNE uniquement (ancré ^...$)
if (Pattern.matches("^(INTERNE|EXTERNE)$", laDem.getModeTransport()) == false) {
    res = false;
}
// ** Ajout : type d'échange STANDARD, SILVER ou GOLD uniquement
if (Pattern.matches("^(STANDARD|SILVER|GOLD)$", laDem.getTypeEchange()) == false) {
    res = false;
}

b) Additional date check: a regex validates the format but not the actual validity of the date (2022-03-33 matches the pattern). We must verify that the date actually exists (strict parsing with SimpleDateFormat.setLenient(false) or LocalDate.parse) and, from a business standpoint, that it is consistent (for example, not later than today's date).

D2.2

Missing JUnit test: create with a valid request

The three existing tests cover invalid cases (transport, exchange, date). The nominal case is missing, where all data is valid and create must return true. We add a valid request to setUp(), then the test:

// Dans setUp() — ligne 16 : une 4e demande entièrement valide
this.dem4 = new DemandeJson(4, "2022-03-20", " ",
        "GOLD", 0, "INTERNE", 44, "A320", 2, 3, null);

// Nouveau test — ligne 44 : demande valide -> create doit réussir
@Test
public void testCreateDemandeValide() {
    boolean result = DemandeService.create(dem4);
    assertEquals("Create avec une demande valide", true, result);
}

Declare the private DemandeJson dem4; field at the top of the class (alongside dem1/dem2/dem3).

Marking scheme points (reminder)

SectionExpectationPoints
ADICP criteria (cases 2 and 6), ER 4/5 impacts, scenario 2/5 measures, cyber influence motives12
BHashing vs encryption, Bcrypt salting, anti-injection prepared statement, 2FA, OTP field, OTP verification + syslog logging26
CElectronic signature / eIDAS, 4 requirements, abuse query, blocking trigger, compatibility modelling, business constraint24
DPOST REST API (201/400), regex checks + date validity, nominal JUnit test18
Total80
Official exam paper © Éducation nationale - published by Réseau CERTA - Éducation nationale (source link). Annotated solutions and methodology © Lockbay Academy.