Security across the whole software-development process: foundations and motivation, security in the analysis phase (CIA triad, attack trees, misuse cases, threat modeling), security in the design phase (secure architecture principles, Kerckhoffs, legacy systems), secure programming in Java (DoS, confidential data, injection/validation, extensibility, secure code, object creation, serialization), security testing and operation, and example attacks with countermeasures (SQL injection, man-in-the-middle), plus the worksheet security examples.
Security — Foundations and Motivation
Why IT security matters, the definitions of security and vulnerability, the challenges, how attacks are planned, and the "security is a process / by design" mindset.
Notes for Why IT security matters and why it is difficult
Why IT security matters and why it is difficult
Security problems arise from insufficient software/planning/code quality (bugs, privilege escalation): the NSA/Snowden revelations, Heartbleed (an OpenSSL bug letting critical data up to the private key be read over the network), OS bugs leaking user info, and billions of accounts (health/credit-card data) exposed yearly (Equifax, Deloitte, Facebook, Google, British Airways).
Security problems are of financial interest to both sides: attackers sell data, mine bitcoins on company machines, or extort firms; victims suffer image damage and significant fines (European data protection: up to €20 million or 4% of global annual turnover). Small, inconspicuous decisions can have huge effects (the ELBA example: a hard-coded DB admin username, AES keys readable from the DB, leading to full DB access and even command-shell injection on the server).
Open design: systems expose ever more external interfaces; attackers can define/manipulate much of the transmitted data, automatically and at scale.
False security understanding: security is seen as just transport encryption, but faulty authentication, insufficient rights management, weak data validation and data leaks also count.
Insufficient understanding: developers combine components/frameworks and estrange from the underlying technology, forming wrong ideas of how it works and is secured.
Own developments: combining ready components still needs new code, creating new unique security problems.
Simplification of development and creative, fast-evolving attacks: easier development without security awareness; attack methods evolve unpredictably, so knowledge must be kept current.
Time/resource limits: projects skip dedicated security experts or shorten security tests (same lesson as the history of software testing — invest deliberately).
Overcomplex technologies and rising functional requirements: many features (some never intended) cause side effects; more functionality (e.g. password recovery, hints, 2FA, SSO beyond email+password) means more code and more error probability.
Per DIN VDE 31000: "Security is a situation in which the risk is no greater than the limit risk"; the limit risk is the greatest still acceptable risk of a technical process/state; absolute security without any risk exists neither in technology nor in nature. Risk is computed as Risk = damage × probability of occurrence.
A vulnerability (Schwachstelle, RFC 4949) is "a flaw or weakness […] that could be exploited to violate a system's security policy." Vulnerabilities arise in the design phase (faulty architecture assumptions), implementation (insecure practice), and assembly/configuration (config errors or wrong expectations of defaults); today the trigger is often a subtle combination of several small problems rather than one cause.
Notes for Exploitable vs. internal vulnerabilities
Exploitable vs. internal vulnerabilities
Exploitable vulnerability
Directly exploitable — e.g. lets an attacker gain more rights than they should, violating integrity, availability or confidentiality (e.g. a buffer overflow leading to machine takeover).
Internal vulnerability
Not directly exploitable, but combined with exploitable vulnerabilities to increase the damage (e.g. rights not restricted sufficiently).
Notes for How an attack is planned and carried out
How an attack is planned and carried out
Reconnaissance of the target: analyse its capabilities, software level, approaches, functionality, hidden data, frameworks.
Analyse the target: examine the gathered info for known vulnerabilities or conceptual gaps.
Identify and exploit vulnerabilities: escalate privileges, trick authentication/authorization, take over accounts (session hijacking, SQL injection).
Establish permanent access: create your own user, install software, even fix the original hole (so copycats can't reuse an auto-found vulnerability).
Cover tracks: e.g. delete log files.
Repeat: work further into the victim's IT landscape (network/system/server to the next).
Notes for Security as a process and cross-cutting guidance
Security as a process and cross-cutting guidance
No software is 100% secure (≥ a minimum number of errors per 1000 lines, some security-critical), so with enough creativity/persistence an entry point is usually found — but exploiting/finding it can be made harder so attackers move to easier targets; how much effort to invest depends on the risk (damage potential × probability), via a cost-benefit analysis.
"Security is a process" (Bruce Schneier): security must be considered in all phases, lived and backed by management, and cover the human component (training) — else users create workarounds (the classic Post-it with the password on the screen). Cost structure mirrors normal defects: the earlier security is considered, the cheaper (a fix costing €1 in requirements costs €50 in system test), plus extra costs like data-protection fines. Privacy & Security by Design is a fixed part of the GDPR; e.g. Datensparsamkeit (data minimization) — store only the data really needed (year of birth or "of age yes/no" instead of the full birth date), the opposite of unchecked "store everything" Big Data.
Security problems occur unavoidably, so security is relevant in all phases to uphold confidentiality/integrity/availability; measures/requirements must be elicited and coordinated; security is a long process — single measures rarely suffice.
Specialized security extensions to development processes exist: Comprehensive Lightweight Application Security Process (CLASP), Microsoft Security Development Lifecycle (SDL), Software Assurance Maturity Model (SAMM).
Security is also a management topic and must be considered from the start (Security by Design) through operation/decommissioning; use standards and standardized libraries; analyse known vulnerabilities; rule of thumb: never neglect input validation.
Security in the Analysis Phase
Eliciting security requirements, the CIA triad, protection classes/CVE-CVSS, and threat-documentation techniques (attack trees, misuse cases, threat modeling).
Notes for Security requirements, protection classes, and risk analysis
Security requirements, protection classes, and risk analysis
The analysis phase elicits functional and non-functional security requirements from all stakeholders, resolving conflicts. Crucially, stakeholders often assume security implicitly rather than stating it, so targeted questioning is needed. Certificates/standards matter (software may need certification), and external evaluations (e.g. penetration tests) help avoid operational blindness.
Security goals follow the CIA triad — Confidentiality (Vertraulichkeit), Integrity (Integrität), Availability (Verfügbarkeit) — and focusing on one affects the others. It can be extended by authenticity or non-repudiation (e.g. BSI IT-Grundschutz).
Protection classes: classify identified faults/requirements by categories (e.g. probability of occurrence and impact) on scales like low/medium/high/very high.
Classification frameworks help compare/analyse vulnerabilities (how urgently to patch): Common Vulnerability Enumeration (CVE) and Common Vulnerability Scoring System (CVSS, which adds the scoring CVE lacks).
Threat/risk analysis: typify threats by target, originator, motivation/intent, probability and impact/cost; then list threats, assess risk, plan measures, and estimate residual risk.
Notes for Threat-documentation techniques
Threat-documentation techniques
Attack tree (Angriffsbaum)
A tree-structured technique (Bruce Schneier) to document threats at an adjustable level of detail; nodes/edges can carry probabilities. Drawback: large attacks quickly become cluttered (e.g. spanning several network levels).
Misuse case
An alternative based on UML use-case notation (Sindre & Opdahl, 2005): the use-case diagram is extended with differently-coloured misuse cases (dark = bad behaviour like attacks/manipulation); can partly be checked with negative testing. Modelling-tool support is scarce.
Threat modeling
Early, stepwise modelling of threats in growing detail to identify threats and dependencies, thinking like a creative attacker (don't assume an attack would never be tried); used e.g. at Microsoft.
Threat modeling proceeds through defined steps: set application scenarios, external dependencies, security assumptions and notes; build data-flow diagrams; define threat types; identify threats in the system; assess their risk; and plan countermeasures.
Security in the Design Phase
How architecture and security relate, the design principles for a secure architecture (incl. Kerckhoffs), and handling legacy systems via the onion model.
Notes for Security in the design phase
Security in the design phase
The design must support the required security; a secure architecture is the necessary basis for a secure implementation, and even a small gap can undo extensive work (weakest link). Security patterns provide template solutions for typical problems; attack patterns model possible attacks, relations and conditions to derive specific requirements/solutions; modelling can use UML with extensions like UMLSec (rarely tool-supported).
Notes for Design principles for a secure architecture
Design principles for a secure architecture
Simplicity (KISS): prefer simple over complex designs — complex designs are more error-prone and need more elaborate testing.
Restrict permissions: give every component only minimal permissions; deny access by default; strict input validation by whitelisting allowed data.
Complete mediation: check all accesses at a central point (e.g. the Java Security Manager or OS tools before dangerous operations).
Open design: security must not depend on secrecy (no security by obscurity — secret details leak eventually, e.g. GSM A5); this includes Kerckhoffs' principleKerckhoffs' principle
Kerckhoffs' principle
Security in encryption must rest only on the secrecy of the key, not on the secrecy of the encryption algorithm.
Secret algorithm details leak sooner or later (e.g. the GSM A5 encryption), so a scheme whose security depends on hiding the algorithm (security by obscurity) is unsafe. This underlies the open-design principle and the "don't invent your own crypto" rule.
Layering (defense in depth): insert several layers between interfaces and core components, each talking only to its neighbours, so an attacker must work through many layers (VMs, sandboxing, chroot help).
Least privilege: need only minimal rights (e.g. no admin rights to run); a compromised app can't unfold full damage without extra escalation. Negative example: Apache long ran as admin to bind port 80, so any of its many holes gave full system access.
Minimize dependencies between systems/services/software (e.g. avoid shared variables/files) so attacks can't compromise several parts at once.
Social components: user acceptance and usability matter — well-meant but burdensome measures backfire (complex password rules → passwords on paper); make secure solutions easy to use (e.g. plug-in USB tokens).
Notes for Kerckhoffs' principle
Kerckhoffs' principle
Security in encryption must rest only on the secrecy of the key, not on the secrecy of the encryption algorithm.
Secret algorithm details leak sooner or later (e.g. the GSM A5 encryption), so a scheme whose security depends on hiding the algorithm (security by obscurity) is unsafe. This underlies the open-design principle and the "don't invent your own crypto" rule.
Notes for Legacy systems and the onion (wrapper) model
Legacy systems and the onion (wrapper) model
Legacy systems are older systems built with different requirements and goals than current ones; projects must often integrate them, but they were not designed for open interfaces and may lack rights management, have insufficient patch levels, or lack input validation (a real current problem in telecom/energy where law forces fast opening of long-closed systems).
Solution — the onion-shell model (Zwiebelschalenmodell): a wrapper around the legacy system's interfaces that validates incoming/outgoing data and integrates new security concepts (e.g. encryption) without changing the legacy software itself.
Secure Programming (Java)
Runtime security, denial of service, protecting confidential data, code injection and validation, extensibility and access rights, secure code, object creation, and serialization.
Notes for Architecture and programming interplay; anti-patterns
Architecture and programming interplay; anti-patterns
A secure architecture can be made insecure by programming errors (missing/faulty certificate checks, insufficient input validation), and a flawless implementation can still be weak due to architecture decisions (no transport encryption, default users with fixed passwords) — so no phase may be neglected.
"The attacker only has to find one flaw, while the defender has to find and fix every flaw" (Bruce Schneier). To structure secure development, use known anti-patterns (known bad behaviour to avoid) and best-practice solutions. The following focus on Java but apply to other languages too.
Notes for Secure programming in Java — runtime security
Secure programming in Java — runtime security
Java provides runtime security (the JRE enforces prescribed behaviour, enabling sandboxed execution — but restrictions must be configured), security-relevant APIs (key management, encryption, authentication; more via libraries like Bouncy Castle), and tools (jarsigning, policytool).
Automatic memory management prevents buffer overflows (a classic C/C++ problem): array accesses are bounds-checked and pointer arithmetic is not explicit.
Bytecode verification checks bytecode for obviously malicious code before execution (do not disable it).
SecurityManager and AccessController check rights restrictions at runtime; policies give fine-grained permission control; multiple ClassLoaders can separate code execution (static fields soften this separation).
Notes for Denial of Service (DoS)
Denial of Service (DoS)
Watch which actions consume unusually many resources; always release resources (often forgotten on error paths where a thrown exception skips release — Java's try-with-resources helps); an integer overflow can defeat resource-limit checks.
Plan against DoS already in the design phase; parsers are a favourite DoS source — use well-tested parsers and standardized formats (XML with schemas) over own developments; ensure correct operation under attack and normal high load.
Dangerous: CPU/memory-heavy computations (large binaries/images/compressed data, complex nested objects, overly detailed logging); manipulated data (ZIP bombs, XML External Entity / 'billion laughs', complex grammars XPath/RegEx, Java deserialization, integer overflows in resource checks); endless loops in parsers (avoidable via configuration).
Integer overflow example: a check off+len > bArray.length can be bypassed if off+len overflows — also test for negatives: if(off < 0 || len < 0 || off+len < 0 || off+len > bArray.length).
Notes for Protecting confidential data
Protecting confidential data
Remove critical info from exceptions (connection strings with user/password; IOExceptions reveal paths/usernames; FileNotFoundExceptions help attackers map the filesystem).
Do not log critical info (passwords, private data); use different log paths by criticality; use known logging frameworks and don't blindly adopt default configs; use separate dev vs production log configs and make it impossible for end users to accidentally enable dev mode.
Remove critical info (passwords, keys) from memory after use — memory is poorly protected (Firewire/Thunderbolt read access, Rowhammer); don't rely on garbage collection; store as char[] or specialized objects and overwrite ASAP; keep it as local as possible.
Never store critical info as plaintext — process passwords with OS APIs, hashes, salts; prefer specialized, deliberately compute-expensive schemes like BCrypt or PBKDF2 to keep hash-cracking slow.
Don't invent your own crypto: many weaknesses need experience to spot, and tiny design choices have big effects (e.g. HMAC ordering — hash before or after encryption?) that even experts find hard, easily weakening encryption unintentionally.
Notes for Code injection and input validation
Code injection and input validation
Code injection & validation matters wherever requests are processed/forwarded: dynamic SQL, XML/HTML generation, calling external components (shell scripts), native methods (JNI, C/C++); many sources are very flexible (HTTP headers, cookies) and can hide code/attacks.
Validate and avoid data from untrusted sources; check data integrity; use whitelists for sources and standardized, proven parsers.
Problematic data can be fully discarded, partly discarded, or repaired — effort and error probability rise left to right; repair can turn harmless into critical data (removing <script> once: <script><script>alert(...)</script></script> still leaves a tag).
Prefer strict whitelisting (define exactly what is allowed, e.g. a credit-card-number format) over blacklisting (only defines what is forbidden — fails against new attacks and is hard to keep current).
Validate always and without exception (escaped chars, alternative encodings, out-of-range values); stop processing incorrect data as early as possible (your validation code can have bugs too); use regex to check structure; only forward correctly validated data; validate native-method inputs in a safer language (Java); prefer existing libraries over own developments.
Always validate incoming data and data from untrusted objects (e.g. plugins); data passed to native methods needs especially careful validation — it prevents state-machine/control-flow corruption (important for auth) and DoS.
Never assume all code comments are read/heeded; check all possible (even unlikely) violations — e.g. a whitelist limiting interfaces.length <= 65535 (one if suffices).
Real JDK example: Proxy.getProxyClass/defineClass (native) crashes when called with more than 65535 interfaces; since Proxy is serializable, a hand-edited serialized form sent over the network enables a remote DoS.
Automatic random testing (fuzzing, used at Microsoft at scale) calls methods/programs with random data and checks for crashes — a crash reveals a data-validation weakness.
Notes for Extensibility and access rights
Extensibility and access rights
Restrict the accessibility of classes/interfaces/methods/fields and of packages, isolate source code, restrict the extensibility of classes/methods, and consider the super/subclass relationship — this reduces the attack surface and prevents unwanted code changes.
Subclasses cannot guarantee encapsulation: a superclass can change the behaviour of non-overridden methods or add new methods, so security checks added in a subclass can be bypassed.
Real JDK example: java.security.Provider extends Properties (extends Hashtable) and secures put/remove with checks; when Hashtable later gained entrySet() (whose Set supports removal), an attacker could bypass the secured remove via Provider.entrySet().remove(key).
Therefore: only subclass when you fully understand and specify what/how is inherited; if unsure, prefer composition over inheritance; when a superclass changes, analyse subclasses and override new methods (e.g. override entrySet() in the Provider subclass).
Notes for Secure code and object creation
Secure code and object creation
Define value types as immutable; return mutable return values only as copies; copy mutable inputs before processing; copy returns from / inputs to untrusted objects; define explicit methods to change state; make as many fields constant as possible (especially public ones).
Public mutable static fields are dangerous (real JDK: public static FuncLoader m_functions[] could be overwritten via FunctionTable.m_functions = my_malicious_table, with program-wide effect since it is static — e.g. reaching the XPathContext to read/alter critical data).
Static fields are identical across the whole JRE (attackable even with multiple ClassLoaders), so make public static fields final; keep mutable statics non-public and encapsulate array access via copies and own methods (return data.clone(); store b.clone() after checkSecurity).
Prefer enums as a data type: they give type safety, support switch (helps not to miss possible values), and constrain the value range by construction.
Don't create security-critical objects via plain constructors; secure their creation; prevent only-partial initialization; constructors should not call overridable methods; ensure classes can't be cloned.
Partial-initialization attack: throwing an exception during construction does not destroy the object — by overriding finalize() an attacker can obtain a partially initialized instance (e.g. a ClassLoader) despite a thrown SecurityException, getting objects they shouldn't be allowed to create.
Countermeasure: make classes final (cannot be subclassed); otherwise ensure partially-initialized objects are unusable (set fields only after all security checks, or use an 'initialized' boolean flag every method checks).
Notes for Serialization
Serialization
Avoid serializing security-critical classes; use a SecurityManager and Java permissions to control (de)serialization; protect serialized data.
Maliciously altered serialized object structures can create error-prone objects and even exploit faults in components the software doesn't actively use but that ship in an included library.
Validate data to be deserialized — e.g. a whitelist of expected classes via a look-ahead ObjectInputStream that checks before deserializing (a blacklist is hard to maintain).
In general avoid deserialization (the protection can be bypassed); never deserialize data from untrusted sources; prefer XML or comparable formats over serialized Java objects.
Security Testing and Operation
Security-relevant tests (penetration testing and its limits, management support) and security during and after the operation phase.
Notes for Security-relevant tests
Security-relevant tests
Failing tests are more than a warning, and unspecified/unknown extensions are possible vulnerabilities. Penetration testing ("penetrate and patch") simulates attacks to find security problems and then patches them (also offered by external firms), but relying on it alone is insufficient.
Penetration testing likely overlooks vulnerabilities; those not (auto-)found are not fixed; the patch often fixes only a symptom rather than the real (e.g. architectural) problem; all systems stay vulnerable until fixes are deployed everywhere; and published patches let attackers find the weakness in unpatched systems.
Management support is required: security measures cost upfront and management must back those costs; long-term savings (comparing old vs new projects' security costs) help get management on board, though that comparison is time-consuming and hard.
Notes for Security during and after operation
Security during and after operation
Operation requires keeping security requirements, defining/meeting SLAsSLAs defined (operation)
Operation requirements and SLAs
Requirements: high stability/fault tolerance (minimal downtime); data security (protection from unauthorized access/loss, emergency plans, backups); documentation for all relevant areas; recoverability (restart/recovery any time); easy analysability/adaptability/configurability; frugality (low CPU/memory use); independence (apps don't interfere); trained staff in place before commissioning.
Service Level Agreements (SLAs): fix criteria for non-functional requirements, set by stakeholders before development and met during operation or penalties apply; define per the SMART principle — Specific, Measurable, Achievable, Reasonable, Time-bound. Examples: service availability, response time under load, time to answer a maintenance request.
Go to block, detecting and reporting security incidents, and responding (patches, information distribution) — with professional, transparent handling of customers; best-practice collections like ITIL help not to overlook anything.
Only operating a software shows whether its security requirements are met; operation, development and security experts must collaborate.
The time after operation also matters: handle the accumulated data, securely deactivate components, proceed in a controlled, planned way.
Example Attacks and Countermeasures
SQL injection and man-in-the-middle attacks with their countermeasures, and the security summary.
Notes for SQL injection
SQL injection
SQL injection typically occurs when SQL statements are built dynamically at runtime from user input, letting attackers modify the statement to read/change/delete more data than intended (Ponemon 2014: 49% of stolen company data related to SQL injection). Shown DB error messages can reveal the schema (e.g. input te'st); tautologies like ' or '1'='1 return all data, and UNION statements/subqueries read further tables.
Countermeasures: validate every input (also from other systems); filter/escape DB-specific characters like quotes (blacklist) and check for valid characters (whitelist); use precompiled/prepared statements with placeholders (prevents statement manipulation); restrict the DB user's privileges (e.g. no delete if read suffices).
Modern best practice: use an OR-mapper like Hibernate with QueryBuilder/Criteria — hides complexity, eases DBMS migration, and security issues are found/fixed faster by its large community than you could yourself.
Notes for Man-in-the-middle (MitM) attacks
Man-in-the-middle (MitM) attacks
A man-in-the-middle attack intercepts traffic via a third party (e.g. routing server↔client traffic through the attacker); it can happen in company networks, public WLANs, or the internet (even by the ISP), and is sometimes used legitimately (packet inspection). In an internal network ARP spoofing is used: forged ARP replies poison the ARP cache with wrong IP/MAC mappings (the forged info must arrive faster than the real info; repeated attempts eventually succeed).
Countermeasures: encrypt traffic (e.g. HTTPS); often via PKIs; use certificate pinning (RFC 7469) to block forged certificates (for a known private server certificates can even be hard-coded); never disable certificate validation in production builds.
Pinning example: a KeyStore holding exactly the one expected 'trusted' certificate initializes a TrustManagerFactory and SSLContext, whose SSLSocketFactory is then used (e.g. with HttpsURLConnection).
Worksheet Security Examples
Not-Invented-Here crypto and Kerckhoffs, the password-comparison code, MAC ordering, Java serialization risk, and trust boundaries / two-factor authentication.
Notes for Not Invented Here — custom crypto and secrecy
Not Invented Here — custom crypto and secrecy
Do not design your own cryptographic algorithm, and do not keep the algorithm secret to gain security.
A self-made "especially secure and efficient" cipher is almost certainly weak — secure crypto needs deep expertise and extensive public scrutiny, so use established, vetted algorithms (Not-Invented- Here is dangerous here). Keeping the algorithm secret is security by obscurity and violates Kerckhoffs' principle: security must rest only on the key's secrecy, because algorithm details leak eventually.
Notes for The password-comparison code
The password-comparison code
Scenario: comparePasswords(userSuppliedPassword, expectedPassword) throws on null and then throws a SecurityException if !Objects.equals(...) (which internally calls String.equals).
Interpretation: The hidden problem is a timing side-channel: String.equals compares character by character and returns at the first mismatch, so the comparison time leaks how much of the password matched, letting an attacker reconstruct it character by character — use a constant-time comparison (e.g. MessageDigest.isEqual). Further issues: the expectedPassword is handled in plaintext (passwords should be stored/compared as salted hashes), and distinct exception messages/types can leak information.
Notes for Least privilege, input validation, and key storage
Least privilege, input validation, and key storage
The worksheet's three recurring learn-from-others-mistakes themes, answerable from the design/implementation principles:
Least privilege: grant only minimal rights and deny by default, so a compromise can't unfold full damage (see the design principles and the Apache-as-admin negative example).
Input validation: always validate untrusted input with whitelists, as early as possible, to prevent injection/DoS/control-flow corruption.
Storage of encryption keys: never store keys/passwords in plaintext or readable from the DB (the ELBA failure); use OS key stores, salted hashes and BCrypt/PBKDF2, and remove keys from memory after use.
Notes for MAC ordering — MAC-then-Encrypt vs. Encrypt-and-MAC vs. Encrypt-then-MAC
MAC ordering — MAC-then-Encrypt vs. Encrypt-and-MAC vs. Encrypt-then-MAC
MAC-then-Encrypt
Compute the MAC over the plaintext, append it, then encrypt both (used by TLS). The receiver must decrypt before it can verify the MAC, so malformed ciphertext is processed before authentication.
Encrypt-and-MAC
Compute the MAC over the plaintext, encrypt the data, append the MAC of the plaintext (used by SSH). The MAC over plaintext can leak information and is verified only after decryption.
Encrypt-then-MAC
Encrypt the data, then compute the MAC over the ciphertext and send both. The receiver verifies the MAC on the ciphertext first and rejects forged/altered data before decrypting.
The order matters: Encrypt-then-MAC is generally considered the most secure (authenticate the ciphertext, reject before decrypting, avoiding padding-oracle-style attacks). A MAC (Message Authentication Code, e.g. HMAC) combines a secret key with a hash so only key-holders can compute it, letting receivers detect tampering — choosing the "wrong" order can silently weaken the whole scheme, which is why you should not invent crypto.
Notes for Java serialization risk
Java serialization risk
Java serialization (added 1997) converts objects to binary/XML and back to exchange data or save program state. Despite sounding useful, it is called "a horrible mistake" with "no reason to use it in any new system" because deserializing untrusted data is dangerous.
Deserialization can instantiate arbitrary objects and trigger side effects/gadget chains, even exploiting faults in unused classes that merely ship in an included library; it also enables DoS.
It is a large, hard-to-control attack surface — so validate with class whitelists (look-ahead), avoid deserialization generally, never deserialize untrusted data, and prefer XML/JSON. General lesson (with the MAC example): small, innocuous-looking details have outsized security impact, so rely on vetted standards rather than convenient built-ins.
Notes for Trust boundaries, two-factor authentication, and obfuscated commands
Trust boundaries, two-factor authentication, and obfuscated commands
Trust boundaries delimit where data/control crosses from a less-trusted to a more-trusted zone; all data crossing inward must be validated/authorized — 'trust is good, control is better'.
Two-factor authentication (pushed by Google/iCloud) adds a second independent factor so a single stolen credential is not enough; for software engineering: don't rely on one safeguard, use layered/defense-in-depth controls.
All-or-nothing authentication is bad: one compromise grants everything; prefer graded, least-privilege access so partial compromise is limited.
Building a trust basis with a server: use encryption + verified certificates (PKI/certificate pinning, even hard-coded certs for known servers) and validate the exchanged data — don't trust data just because it came from 'the server'.
The obfuscated %TEMP%/%ProgramFiles% string is an obfuscated (encoded/concatenated) shell command built to evade naïve filters — like obfuscated SQL injection, it shows that blacklist filtering fails and inputs must be whitelisted/validated rather than pattern-blocked (Code Obfuscation).