Why a Firewall Alone Isn't Enough: An Intro to Security Engineering
A lot of engineers’ mental model of security stops at “we have a firewall.” That’s not wrong, exactly — it’s just one layer of a system that needs several. A firewall decides what traffic is allowed to reach your network or service in the first place. It says nothing about whether the traffic it does let through is malicious, whether your own code has a vulnerability, or whether someone is already inside doing something they shouldn’t be. Those are different problems, and each one below is the tool built to answer it.
This is an introduction, not a deep dive into any single tool — the goal is to understand what each layer is actually for, so you know which gap you’re closing when you add one.
Why “the firewall is our security” fails
Section titled “Why “the firewall is our security” fails”A firewall operates mostly at the network level: it allows or blocks traffic based on rules like source, destination, port, and protocol. That’s genuinely useful — it’s why your database isn’t reachable from the public internet. But it has clear blind spots:
- It generally can’t tell a legitimate HTTP request from a malicious one if both arrive on port 443 — a SQL injection payload looks like normal traffic at the network layer.
- It does nothing once a request is inside your network — if an attacker compromises one service, a firewall won’t stop them from moving laterally to another.
- It says nothing about vulnerabilities in your own application code, your dependencies, or your container images.
- It doesn’t help you notice that something bad already happened, or figure out what to do about it.
This is the idea behind defense in depth: no single control is assumed to be sufficient, so you layer several, each covering a different failure mode. The rest of this article walks through the layers most teams are missing.
Detecting malicious traffic: IDS and IPS
Section titled “Detecting malicious traffic: IDS and IPS”An Intrusion Detection System (IDS) monitors network or host activity and flags suspicious behavior — known attack signatures, unusual traffic patterns, policy violations. It’s passive: it tells you something looks wrong, but doesn’t act on it.
An Intrusion Prevention System (IPS) does the same detection, but sits in-line and can actively block or drop the offending traffic in real time.
Network traffic → Firewall (allow/deny by rule) → IDS/IPS (inspect content, detect/block attacks) → ApplicationThe distinction from a firewall: a firewall asks “is this source/port/protocol combination allowed at all?” An IDS/IPS asks “does the content of this allowed traffic look like an attack?” — things like a port scan, a known exploit signature, or an anomalous spike in failed login attempts.
In practice, most teams encounter IDS/IPS capability bundled into a Web Application Firewall (WAF) for HTTP traffic specifically, or as a feature of their cloud provider (AWS GuardDuty, Azure Network Watcher) or a dedicated tool like Suricata or Snort for network-level monitoring.
Worth knowing: IDS/IPS are signature- and pattern-based by nature, which means they’re good at catching known attack patterns and weaker against novel ones. They reduce risk; they don’t eliminate it.
Knowing what happened: SIEM
Section titled “Knowing what happened: SIEM”Once you have a firewall, an IDS/IPS, application logs, and cloud provider logs, you have a new problem: the signal is scattered across many systems, in different formats, at a volume no person can watch manually.
A Security Information and Event Management (SIEM) system centralizes logs and events from across your infrastructure — network devices, servers, applications, cloud services — and correlates them to surface things that matter. A single failed login is noise. A hundred failed logins across different accounts from the same IP, followed by one success, is a pattern a SIEM can flag that no single log line would reveal on its own.
What a SIEM typically does:
- Aggregates logs and events from many sources into one place.
- Correlates events across sources to detect patterns a single source wouldn’t reveal.
- Alerts security teams when a correlation matches a known threat pattern.
- Retains historical data for investigation after an incident (“what did this account do in the 48 hours before we noticed?”).
Common tools: Splunk, Elastic Security (the ELK stack), Microsoft Sentinel, and open-source options like Wazuh. For a small team, even centralizing structured logs into one searchable place with basic alerting rules is a meaningful step toward this, before you need a dedicated SIEM product.
Finding vulnerabilities before attackers do: SAST and DAST
Section titled “Finding vulnerabilities before attackers do: SAST and DAST”Everything above is about detecting and responding to attacks. SAST and DAST are about finding the vulnerabilities an attack would exploit — ideally before the code ships.
SAST (Static Application Security Testing)
Section titled “SAST (Static Application Security Testing)”SAST analyzes your source code without running it — looking for known-dangerous patterns: SQL built with string concatenation, hardcoded secrets, unsafe deserialization, missing input validation. It runs early: in your editor, in a pre-commit hook, or in CI on every pull request. This is the “shift left” idea — catching a vulnerability in a code review is far cheaper than catching it in production.
name: SASTon: [pull_request]jobs: semgrep: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: returntocorp/semgrep-action@v1 with: config: p/owasp-top-ten// What SAST is built to catch — string-concatenated SQLquery := "SELECT * FROM users WHERE id = '" + userID + "'" // flagged: SQL injection riskdb.Query(query)
// vs. the fix it's nudging you towarddb.Query("SELECT * FROM users WHERE id = $1", userID)Common tools: Semgrep, SonarQube, CodeQL (built into GitHub code scanning), gosec for Go specifically. Closely related: SCA (Software Composition Analysis) tools like Dependabot, Snyk, or govulncheck, which scan your dependencies for known CVEs rather than your own code — a different but equally important check, since most codebases have far more third-party code than first-party code.
Limitation: SAST reasons about code structure, not runtime behavior, so it produces false positives and can miss vulnerabilities that only manifest when the application is actually running — which is exactly the gap DAST covers.
DAST (Dynamic Application Security Testing)
Section titled “DAST (Dynamic Application Security Testing)”DAST tests your running application from the outside, the way an attacker would — sending malicious inputs to live endpoints and observing the actual response, with no knowledge of the source code. This is effectively automated, repeatable pentesting, run against a staging environment as part of your pipeline.
# .gitlab-ci.yml (excerpt)dast: stage: test image: owasp/zap2docker-stable script: - zap-baseline.py -t https://staging.myapp.com -r zap_report.html artifacts: paths: [zap_report.html]DAST catches things SAST structurally can’t — misconfigurations that only exist in the deployed environment, authentication bypasses that depend on actual request/response behavior, issues in third-party components you don’t have source access to.
Common tools: OWASP ZAP, Burp Suite’s automated scanner, Nuclei for templated vulnerability checks.
SAST vs. DAST, side by side:
| SAST | DAST | |
|---|---|---|
| Looks at | Source code | Running application |
| Runs | Early (commit, PR, build) | Later (staging, pre-release) |
| Needs the app running? | No | Yes |
| Good at | Code-level issues, secrets, unsafe patterns | Runtime behavior, config, auth flows |
| Blind to | Runtime-only issues, environment misconfig | Anything not reachable via an exposed interface |
Neither replaces the other — they catch different classes of issues at different stages, which is why mature pipelines run both.
How these layers fit together
Section titled “How these layers fit together”Mapped against when each one operates:
Write code ──► SAST + SCA (CI, every PR) │Build & package ──► Container/image scanning │Deploy to staging ──► DAST (automated dynamic scan) │Running in production: Network traffic ──► Firewall ──► IDS/IPS All of the above ──► SIEM (centralized logging, correlation, alerting) │Periodically ──► Manual penetration testing (human-driven, catches business-logic flaws automation misses)The firewall and IDS/IPS protect the network boundary and the traffic crossing it. SAST and DAST reduce the number of vulnerabilities that exist to be exploited in the first place. SIEM ties it together by giving you visibility across all of it, so when something does get through, you can actually see it happened and respond — rather than finding out from a customer or a headline.
This is also roughly the arc from the previous articles on this site: eJPT and PWPA are about the manual, offensive side of this picture — the human penetration testing step at the bottom of the diagram, which automated DAST scans don’t fully replace because they catch business-logic flaws and chained exploits automation tends to miss.
A practical starting point for a small engineering team
Section titled “A practical starting point for a small engineering team”You don’t need all of this on day one. A reasonable order to add layers in:
- SAST + SCA in CI — cheapest to add, catches real issues before merge, minimal ongoing cost.
- A WAF in front of public-facing services — covers a meaningful chunk of IDS/IPS-style protection for HTTP traffic specifically, usually a checkbox on your cloud provider or CDN.
- Centralized, structured logging — even without a full SIEM, get logs in one searchable place with basic alerts on auth failures and error spikes.
- DAST against staging — automate a baseline scan before each release.
- A SIEM, and/or dedicated IDS/IPS — once you have enough infrastructure and signal that manual log review genuinely doesn’t scale.
- Periodic manual penetration testing — automated tools don’t catch everything; a human periodically trying to break your specific business logic still matters.
Final thought
Section titled “Final thought”None of these tools are a substitute for secure coding practices, and no combination of them is “done” — security is a continuous process, not a checklist you complete once. But the core idea is simple: a firewall controls what gets in, and almost everything else in this list exists because what gets in isn’t the only thing that matters — what’s already inside, what’s in your own code, and whether you’d even notice if something went wrong are separate problems that need their own tools.
Learning resources
Section titled “Learning resources”- OWASP Top 10 — the vulnerability classes SAST, DAST, and WAFs are largely built to catch.
- OWASP DevSecOps Guideline — integrating these practices into a software delivery pipeline.
- NIST SP 800-94: Guide to Intrusion Detection and Prevention Systems — a free, detailed reference on IDS/IPS.
- Semgrep Documentation — a widely used open-source SAST tool.
- OWASP ZAP — a free, open-source DAST tool.
- MITRE ATT&CK — a knowledge base of real-world attacker behavior, useful context for what IDS/IPS and SIEM correlation rules are actually looking for.