PLC Cybersecurity & IEC 62443: Protecting Industrial Networks in the Connected Age

Your PLC is now on the network — and attackers know it. Learn IEC 62443 defense-in-depth, zone segmentation, access control patterns, and how to write Structured Text that resists tampering.

Why a PLC needs security now

In 2010, Stuxnet showed that a PLC can be the target of a cyberattack. Attacks on industrial control systems have grown since then. The 2021 Oldsmar water treatment hack and the 2022 Pipedream/Incontroller toolkit, which targeted Schneider and Omron PLCs, are the public cases; many incidents are never reported. If your PLC touches a network, even one you believe is "air-gapped", it needs protecting.

IEC 62443 (published jointly with ISA as ISA/IEC 62443) is the international standard for industrial automation cybersecurity. This article covers the parts a controls engineer works with day to day: the network architecture, the protections on the PLC itself, and Structured Text patterns that detect tampering and resist it.

Defense in depth: the castle model

IEC 62443 is built on defense in depth: several layers of protection, so that an attacker who gets through one layer still does not control the whole system. The layers map onto a castle like this:

LayerProtectionAnalogy
Enterprise NetworkFirewall, DMZCastle walls
Plant Network (L3)IDMZ, segmentationInner bailey
Control Network (L2)VLAN isolation, ACLsKeep
Device Level (L1/L0)Hardened PLCs, firmwareCrown jewels

The Purdue model (updated)

Level 5: Enterprise Network (ERP, email, internet)
         ─── Corporate Firewall ───
Level 4: Site Business (MES, historian server)
         ─── IDMZ (Industrial DMZ) ───
Level 3: Site Operations (SCADA servers, engineering stations)
         ─── Control System Firewall ───
Level 2: Area Control (PLCs, DCS controllers)
         ─── Network Segmentation ───
Level 1: Basic Control (I/O modules, drives, sensors)
Level 0: Physical Process (motors, valves, instruments)

The boundary to defend hardest is the IDMZ (Industrial Demilitarized Zone). No traffic should pass directly between Levels 4-5 and Levels 0-3. Instead, data crosses through broker services that sit in the IDMZ, such as data diodes, OPC UA aggregation servers or replicated databases.

Zones and conduits

IEC 62443-3-2 divides a system into zones, which are groups of assets with the same security requirements, and conduits, which are the communication paths between zones. On the PLC side, a zone can be described as a structure that holds its security level and the source addresses it accepts, with a function that checks an incoming address against that list:

// PLC-side: Zone identity and access validation
TYPE SecurityZone :
STRUCT
    ZoneID        : INT;
    ZoneName      : STRING[20];
    SecurityLevel : INT;        // SL1 to SL4
    AllowedSources: ARRAY[1..16] OF STRING[15]; // Allowed IP addresses
    NumAllowed    : INT;
END_STRUCT;
END_TYPE

FUNCTION FC_IsAllowedSource : BOOL
VAR_INPUT
    SourceIP     : STRING[15];
    Zone         : SecurityZone;
END_VAR
VAR
    i : INT;
END_VAR

FOR i := 1 TO Zone.NumAllowed DO
    IF Zone.AllowedSources[i] = SourceIP THEN
        FC_IsAllowedSource := TRUE;
        RETURN;
    END_IF;
END_FOR;

FC_IsAllowedSource := FALSE;

Access control in the PLC program

Authenticating commands

By default a PLC accepts a command from any device that can reach it. Add a challenge-response check, or at the very least a session token. The block below compares a token with a shared secret, counts rejections, and locks out all commands for 60 seconds after five failures in a row:

FUNCTION_BLOCK FB_CommandAuth
VAR_INPUT
    IncomingToken  : DWORD;
    CommandCode    : INT;
    SourceID       : INT;
END_VAR
VAR_OUTPUT
    Authorized     : BOOL;
    RejectionCount : DINT;
END_VAR
VAR
    ValidToken     : DWORD := 16#A5B4C3D2;   // Shared secret (rotate periodically)
    LastRejectTime : STRING[20];
    ConsecRejects  : INT := 0;
    LockoutActive  : BOOL := FALSE;
    tmrLockout     : TON;
END_VAR

Authorized := FALSE;

// Lockout after too many failed attempts
tmrLockout(IN := LockoutActive, PT := T#60S);
IF LockoutActive THEN
    IF tmrLockout.Q THEN
        LockoutActive := FALSE;
        ConsecRejects := 0;
        tmrLockout(IN := FALSE);
    END_IF;
    RETURN;   // Reject everything during lockout
END_IF;

// Validate token
IF IncomingToken = ValidToken THEN
    Authorized := TRUE;
    ConsecRejects := 0;
ELSE
    Authorized := FALSE;
    RejectionCount := RejectionCount + 1;
    ConsecRejects := ConsecRejects + 1;
    
    // Lockout after 5 consecutive failures
    IF ConsecRejects >= 5 THEN
        LockoutActive := TRUE;
        // Log: Potential brute-force attack from SourceID
    END_IF;
END_IF;

Protecting critical parameters from writes

A setpoint that an HMI or a remote client can write should check two things before it accepts a new value: whether the writer's authorisation level is high enough, and whether the value is inside its limits. This block rejects the write if either check fails and keeps the old value:

FUNCTION_BLOCK FB_ProtectedParameter
VAR_INPUT
    NewValue       : REAL;
    WriteRequest   : BOOL;
    AuthLevel      : INT;          // 0=Operator, 1=Engineer, 2=Admin
    RequiredLevel  : INT := 1;     // Minimum auth level to change
END_VAR
VAR_OUTPUT
    CurrentValue   : REAL;
    WriteAccepted  : BOOL;
    WriteRejected  : BOOL;
    LastChangeBy   : INT;
END_VAR
VAR
    _value         : REAL;
    _minLimit      : REAL := 0.0;
    _maxLimit      : REAL := 100.0;
END_VAR

WriteAccepted := FALSE;
WriteRejected := FALSE;

IF WriteRequest THEN
    IF AuthLevel >= RequiredLevel THEN
        IF NewValue >= _minLimit AND NewValue <= _maxLimit THEN
            _value := NewValue;
            WriteAccepted := TRUE;
            LastChangeBy := AuthLevel;
        ELSE
            WriteRejected := TRUE;
            // Log: Out-of-range write attempt
        END_IF;
    ELSE
        WriteRejected := TRUE;
        // Log: Unauthorized write attempt — auth level insufficient
    END_IF;
END_IF;

CurrentValue := _value;

Detecting anomalies in the PLC

The PLC can spot some suspicious activity itself. This block compares the scan time, the communication request rate and the write rate with expected limits, flags connections from unknown addresses, and sets a threat level and an alert message:

FUNCTION_BLOCK FB_AnomalyDetector
VAR_INPUT
    Enable          : BOOL;
    // Monitor these for anomalies
    ScanTimeActual  : TIME;
    CommRequestRate : INT;       // Requests per second
    WriteAttempts   : INT;       // HMI write commands per scan
    UnknownSourceIP : BOOL;      // Connection from unknown IP
END_VAR
VAR_OUTPUT
    ThreatLevel     : INT;       // 0=Normal, 1=Low, 2=Medium, 3=High, 4=Critical
    AlertMessage    : STRING[80];
    TotalAlerts     : DINT;
END_VAR
VAR
    NormalScanTime  : TIME := T#10MS;
    MaxCommRate     : INT := 100;
    MaxWriteRate    : INT := 10;
END_VAR

ThreatLevel := 0;
AlertMessage := '';

IF NOT Enable THEN RETURN; END_IF;

// Check 1: Scan time anomaly (CPU overload = possible DoS)
IF ScanTimeActual > (NormalScanTime * 3) THEN
    ThreatLevel := 2;
    AlertMessage := 'Abnormal scan time — possible DoS attack';
    TotalAlerts := TotalAlerts + 1;
END_IF;

// Check 2: Excessive communication requests (scanning/probing)
IF CommRequestRate > MaxCommRate THEN
    ThreatLevel := 3;
    AlertMessage := 'Excessive comm requests — possible network scan';
    TotalAlerts := TotalAlerts + 1;
END_IF;

// Check 3: Rapid write attempts (brute force or fuzzing)
IF WriteAttempts > MaxWriteRate THEN
    ThreatLevel := 3;
    AlertMessage := 'Rapid write attempts — possible attack';
    TotalAlerts := TotalAlerts + 1;
END_IF;

// Check 4: Connection from unknown source
IF UnknownSourceIP THEN
    ThreatLevel := 4;
    AlertMessage := 'Connection from unauthorized IP address';
    TotalAlerts := TotalAlerts + 1;
END_IF;

Hardening checklist

ActionPriorityIEC 62443 Reference
Change default passwords on all devicesCriticalSR 1.5
Disable unused communication portsCriticalSR 7.7
Enable encrypted communication (TLS/OPC UA)HighSR 4.1
Implement network segmentation (VLANs)HighSR 5.2
Restrict physical access to control cabinetsHighSR 2.1
Enable audit logging on PLCMediumSR 2.8
Implement firmware version verificationMediumSR 3.4
Establish incident response proceduresMediumSR 6.2
Conduct regular vulnerability assessmentsMediumSR 3.3
Use application whitelisting on engineering stationsLowSR 3.2

The measures in brief

ConceptImplementation
Defense-in-depthMultiple layers: network, zone, device, application
IDMZNo direct traffic between enterprise and control networks
Zone modelGroup assets by security level, control conduits between zones
Command authenticationToken validation with brute-force lockout
Parameter protectionAuth-level gated writes with range validation
Anomaly detectionMonitor scan time, comm rate, write rate, source IPs
HardeningSystematic checklist based on IEC 62443 requirements
Antivirus on a PLC is not how OT security works. The protection comes from the architecture and the segmentation, and from people who keep watching the logs and alerts. Design it into the system from day one rather than bolting it on after an incident.