Secure From Scratch
Effective Secure Coding

A different way to think about secure coding.

Security starts with everyday coding decisions. The book is built around habits that make safer choices the natural way to write code - before a vulnerability needs to be found and fixed.

13 language-agnostic secure-coding habits 10 focused deep dives Java + Spring examples, principles for any stack
Effective Secure Coding: Part I - Building Safer Features, Java Spring Edition book cover
Go deeper than the Amazon page

The ideas, experiments, code, and resources behind the book

Amazon A+ is intentionally compact. This page is where the longer reasoning lives - including code, related talks, workshop paths, and books I recommend reading alongside mine.

Make secure coding the natural path

Three examples of how the habits work

Chaotic input passing through validation and becoming a trusted value
1

Trust what you've proven

Turn untrusted input into values whose meaning has already been checked, then carry that trust forward through the code.

A complex dangerous machine beside a safer constrained interface
2

Design safer choices

Use constrained types, purpose-built APIs, and secure defaults so the easiest implementation path is also a safer one.

A protected feature flow from input and authorization to storage and output
3

Secure the whole feature

Follow security through the complete feature - input, authorization, files, services, storage, errors, and output.

A taste of how this book thinks

Start with the security property, then form the habit

Effective Secure Coding is built around secure habits. Each habit centers on a security property we want to preserve or enforce - and on making that property the natural way to write code.

This way of thinking sometimes leads me away from familiar secure-coding advice. Here is one example: "Use an ORM." That is common advice for preventing SQL injection.

My preferred habit is: Keep query structure and data structurally separate. Once I have that property, I can choose an interface that preserves it while still taking advantage of the database.

String concatenation breaks the boundary by inserting data directly into SQL code:

C# - code and data mixed
var sql = "SELECT * FROM Users WHERE Name = '" + name + "'";

An interpolation-aware database API can keep the value parameterized:

C# - parameterized interpolation
db.Users.FromSql(
    $"SELECT * FROM Users WHERE Name = {name}");

A SQL DSL can make the separation part of the query structure:

Java - jOOQ SQL DSL
dsl.selectFrom(USER)
   .where(USER.NAME.eq(name))
   .fetch();

The latter two preserve the property I care about: the interface keeps query structure and data separate.

Why keep SQL visible?

So why do I prefer keeping SQL visible - through a DSL or parameterized SQL - instead of using an ORM? I want the database to participate in the design.

I approach databases as both a developer and a DBA. I want the database itself enforcing security and correctness where it can.

A FOREIGN KEY can make an invalid relationship impossible to store; a CHECK constraint can reject invalid state; and a UNIQUE constraint can enforce a rule correctly when requests race. Views can provide stable read interfaces while the schema evolves, while stored procedures can expose specific write capabilities without granting general table-update permission.

Read accessApproved views
Execute permissionTransferMoney
Direct write permissionAccounts UPDATE denied
This application may transfer money. It may not arbitrarily change account balances.

SQL can change the shape of the solution

Consider a money transfer. An object-oriented persistence model naturally leads toward loading two account entities, changing both objects, and saving the changes:

Java - object-oriented persistence
var from = accountRepository.findById(fromId).orElseThrow();
var to   = accountRepository.findById(toId).orElseThrow();

from.setBalance(from.getBalance().subtract(amount));
to.setBalance(to.getBalance().add(amount));

accountRepository.save(from);
accountRepository.save(to);

The application now has several steps whose transaction and concurrency behavior must be correct. The relational model lets us think about the operation as a change to a set of rows:

SQL - one set-based operation
UPDATE Account
SET Balance = Balance +
    CASE Id
        WHEN :from THEN -:amount
        WHEN :to   THEN  :amount
    END
WHERE Id IN (:from, :to);

-- Preconditions such as sufficient funds are omitted here for clarity.

With the appropriate preconditions and constraints, one business operation can become one atomic database statement. Keeping SQL visible keeps that design option visible too.

Keep dangerous flexibility behind a constrained interface

The same habit applies when SQL genuinely needs to be dynamic. The application can receive a constrained database operation instead of arbitrary write permission.

A stored procedure can accept a requested column, verify that the identifier exists in database metadata, safely quote it, keep values parameterized, and execute the resulting operation using narrowly scoped database permissions.

This keeps the dangerous capability behind a safer interface - a pattern that appears throughout Effective Secure Coding.

Why am I telling you this?

Because this is a sample of how the book approaches secure coding. Take familiar security advice and ask: What property actually makes this safe? Then ask: Which habit can make that property the natural way to write the code? Then preserve the useful capabilities underneath whenever you can.

Sometimes that leads directly to established best practice. Sometimes it leads somewhere more opinionated - such as my preference for a typed SQL DSL and a deliberately designed database API over an ORM.

The idea is to develop secure-coding habits you can reason from, so you can make good decisions when the framework, language, database, or threat changes.

Bonus example

Dynamic SQL without SQL injection

Values are easy to parameterize. Identifiers such as a user-selected column name are different. A safe pattern is to validate dynamic structure against a trusted source, quote the validated identifier, and keep every value parameterized.

Six-step flow from user-selected column through web server and stored procedure to column validation, SQL construction, and safe execution

Suppose a UI legitimately allows the user to choose which column to search. SQL parameters cannot turn @Column into an identifier. In SQL Server, the procedure can validate the identifier against sys.columns before it is ever inserted into SQL structure.

SQL Server - validate identifier, parameterize value
CREATE PROCEDURE dbo.FindUser
    @Column sysname,
    @Value  nvarchar(200)
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS (
        SELECT 1
        FROM sys.columns
        WHERE object_id = OBJECT_ID(N'dbo.Users')
          AND name = @Column
    )
        THROW 50000, 'Invalid column', 1;

    DECLARE @sql nvarchar(max) =
        N'SELECT * FROM dbo.Users WHERE '
        + QUOTENAME(@Column)
        + N' = @Value';

    EXEC sys.sp_executesql
        @sql,
        N'@Value nvarchar(200)',
        @Value = @Value;
END;
The split matters. The column name becomes SQL structure only after it has been proven to be a real column. The value never becomes SQL structure. QUOTENAME() safely delimits the validated identifier, and sp_executesql keeps the value parameterized.

An input such as Name]; DROP TABLE Users;-- simply fails the sys.columns lookup. If the operation intentionally permits only a subset of real columns, add that business rule as an additional allowlist.

SQL Server permissions note for dynamic SQL

Static SQL inside a stored procedure can rely on ownership chaining when owners align. Dynamic SQL is compiled as a separate batch, so an application account with no underlying table rights needs a deliberately scoped execution context or a signed module when the procedure must exercise additional permissions. Keep that extra authority as narrow as the procedure's job.

Build your secure-coding bookshelf

Good books that approach the problem from different angles

I recommend reading broadly. These books overlap with Effective Secure Coding in useful ways, and each emphasizes a different part of the secure-development problem. For older books, I call out where the principles still hold but the technology has aged.

Alice and Bob Learn Secure Coding

Tanya Janca - Wiley, 2025

Read it for: a security-practitioner's view of what developers need to know - vulnerabilities, attack patterns, defensive controls, and approachable explanations of application security.

How my book differs: Tanya's book comes primarily from the security side and teaches security to developers. Effective Secure Coding starts from the development side - the everyday design and implementation habits that can make safer code the natural result.

Publisher page

Secure by Design

Dan Bergh Johnsson, Daniel Deogun, Daniel Sawano - Manning, 2019

Read it for: design-driven security, domain primitives, secure validation, error handling, and security thinking across modern architectures.

How my book differs: this is the closest philosophical relative. My focus is narrower and more developer-at-the-keyboard: habits used while implementing complete features, with repeated emphasis on safe interfaces and natural secure choices.

Publisher page

Iron-Clad Java

Jim Manico, August Detlefsen - McGraw Hill / Oracle Press, 2014

Read it for: a deep Java web-security reference covering authentication, access control, data protection, injection, file handling, logging, and the secure development lifecycle.

Age note: published in 2014. The security principles are still useful, but some Java APIs, libraries, and framework-specific guidance predate today's Spring and Java ecosystem.

How my book differs: my book is organized around habits for building safer features rather than around vulnerability and defense categories, and it brings those habits into a current Java/Spring and AI-assisted-development context.

Publisher page

Secure Coding: Principles and Practices

Mark G. Graff, Kenneth R. van Wyk - O'Reilly, 2003

Read it for: foundational secure-development thinking across architecture, design, implementation, testing, and operations.

Age note: published in 2003. It is valuable as a foundational text, but many implementation details come from a very different software and threat landscape.

How my book differs: Effective Secure Coding concentrates on contemporary feature-level coding habits and concrete implementation decisions rather than covering the full software lifecycle.

Publisher page
More useful material

Resources to keep beside the book

Free reference

OWASP Cheat Sheet Series

Focused implementation guidance when you need the details of a particular security control.

Open the cheat sheets
Verification

OWASP ASVS

A structured set of application-security requirements that complements habit-oriented development with a verification target.

Open ASVS
Safer APIs

OWASP Untrust

Experiments and libraries exploring how trust transitions, constrained types, and safer APIs can guide both human developers and coding agents.

View on GitHub
Database thinking

jOOQ

A typed SQL DSL that keeps the relational model visible while giving application code structured query construction and parameter binding.

Explore jOOQ