Course outline

Java / Advanced / Lesson 17

Secure boundaries and untrusted input

Keep values separate from executable structure, validate resource budgets and domain rules, and protect secrets and diagnostic evidence at Java application boundaries.

About 5 min readContent reviewed
On this page

Lesson goals

  • Distinguish validation, authorization, and parameterization.
  • Bound parsing and reject unsafe deserialization assumptions.
  • Use cryptographic and diagnostic tools for their intended purpose.

Define trust and resource limits explicitly

Untrusted input includes files, messages, configuration supplied by another party, and values previously stored without a trusted validation guarantee. Validate type, format, range, size, and allowed state transitions at the appropriate boundary. Validation is not authorization: a well-formed account identifier may still refer to another user's account. Derive access scope from a trusted identity and enforce it consistently.

A domain code can have a strict ASCII format while a person's name legitimately contains Arabic or punctuation. Do not apply one blanket character blacklist to every field. Bound input before expensive parsing, decompression, regular-expression work, or allocation. A parser that accepts the data does not prove the resulting request is permitted or affordable under concurrency.

Validate a domain format without inventing repairs

The example accepts a five-character product code matching two uppercase Latin letters, a hyphen, and two ASCII digits. It rejects null and every other format rather than trimming, uppercasing, or substituting data silently. Such normalization may be valid in another contract, but it must be a deliberate rule with collision handling. This is a product-code policy, not a rule for human names.

Validate lengths before applying a potentially expensive pattern and choose a simple bounded expression. Java's regex engine supports constructs whose work can grow badly on adversarial input, so pattern design and size limits both matter. Return a stable public rejection while retaining only necessary restricted diagnostic context. Never include secrets or full personal records in exception messages just to aid debugging.

java A bounded product-code contract
public class Main {
static String requireCode(String value) {
 if(value==null || value.length()!=5 || !value.matches("[A-Z]{2}-[0-9]{2}"))
  throw new IllegalArgumentException("invalid product code");
 return value;
}
 public static void main(String[] args) throws Exception {
System.out.println(requireCode("AB-12"));
 }
}
Expected output
AB-12

The valid synthetic code is returned unchanged. The method rejects absent or nonmatching values instead of silently inventing a code.

Keep data out of command structure

For JDBC, bind values through PreparedStatement parameters rather than concatenating them into SQL text. Parameters do not substitute table identifiers or sort keywords; those must come from a fixed approved mapping when dynamic structure is required. Parameterization also does not authorize the selected account or make transaction scope correct. Keep these review questions separate.

The fragment assumes an already authorized connection and a validated accountId; it is not a complete runnable application and opens no real connection in this course. Similar care applies to process execution: passing separate ProcessBuilder arguments avoids a shell-parsing boundary only when a shell is not invoked, and the target tool still interprets its own options. Validate permitted operations as well as values.

java Illustration: a bound JDBC value on an existing authorized connection
try (var statement = connection.prepareStatement(
    "SELECT display_name FROM account WHERE account_id = ?")) {
    statement.setLong(1, accountId);
    try (var rows = statement.executeQuery()) {
        while (rows.next()) {
            System.out.println(rows.getString(1));
        }
    }
}

connection and accountId are contextual inputs, so this fragment is non-runnable and is never connected to a service.

Use hashes and secrets for their actual guarantees

SHA-256 can calculate a content digest, but an unkeyed digest does not authenticate the sender and a fast general-purpose hash is not a complete password-storage design. The example hashes public synthetic text and formats the result; no secret is generated, stored, or sent. Password handling needs an approved password-hashing design and policy beyond this checksum example.

Use SecureRandom for security-sensitive randomness and avoid logging tokens or keys. Transport security also needs endpoint and certificate validation; disabling validation to suppress a connection error changes the trust boundary. Secret lifecycle includes creation, distribution, rotation, revocation, and access control. An encrypted field is not safe if every component can freely decrypt and print it.

java A digest of public synthetic content
public class Main {

 public static void main(String[] args) throws Exception {
byte[] digest=java.security.MessageDigest.getInstance("SHA-256")
 .digest("abc".getBytes(java.nio.charset.StandardCharsets.UTF_8));
System.out.println(java.util.HexFormat.of().formatHex(digest));
 }
}
Expected output
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

This verifies deterministic hashing of abc. It is neither a password hash recommendation nor proof of sender authenticity.

Review rich parsers and failure evidence

Do not deserialize arbitrary native Java object streams from untrusted sources. ObjectInputFilter can restrict classes and graph limits for supported use cases, but filtering is one defense rather than permission to accept any object graph. Prefer a simple explicit data format with a schema, size limits, and domain validation. XML and archive processing also need reviewed external-resource and expansion policies.

Security tests should cover unauthorized but well-formed identifiers, oversized inputs, malformed encodings, dangerous command structure, and rejected data without state change. Protect heap dumps, recordings, logs, and exception traces because they can contain sensitive values. A secure API rejects narrowly, leaves state consistent, and provides enough controlled evidence for diagnosis without turning the public response into a disclosure channel.

Common errors and fixes

SQL injection despite valid-looking input

Why it happens
Values were concatenated into executable SQL structure.
How to fix it
Bind values and independently enforce authorization.
Prevent it next time
Review the final JDBC command boundary.

A checksum was treated as sender authentication

Why it happens
An unkeyed digest was assigned a guarantee it does not provide.
How to fix it
Use an approved authenticated protocol or keyed signature design.
Prevent it next time
Document each cryptographic primitive's purpose.

Sensitive data appeared in logs

Why it happens
Diagnostic detail crossed the intended disclosure boundary.
How to fix it
Restrict, redact, and rotate exposed secrets according to the incident policy.
Prevent it next time
Test error responses and logging with synthetic secret markers.

Check your understanding

1. Does a valid accountId and a bound JDBC parameter prove the caller may read it?

Show worked solution

No. Validation proves format or range, and binding preserves value semantics. Authorization must derive permitted scope from trusted identity and verify that the requested account belongs within it. Test a well-formed identifier owned by another user.

2. An import is compressed to 1 MB but expands to 5 GB. Which limit matters?

Show worked solution

Bound both compressed input and expanded data, plus entry count and processing work where relevant. The compressed file size alone does not constrain memory or disk cost. Reject before exceeding the approved resource budget and keep partial state isolated.

Key takeaways

  • Validation, binding, authorization, and resource limits are complementary.
  • A hash does not automatically authenticate or safely store a password.
  • Rich parsing and diagnostic artifacts need explicit trust boundaries.

Official references