Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Gray-Box Security Notes for WebGoat 8: Defensive Patterns and Secure Implementations

Tech 1

SQL Injection

  • Risk indicators

    • String-concatenated predicates, e.g., building WHERE clauses from raw request parameters.
    • Dynamic DDL/DCL powered by user input (ALTER, GRANT, DROP).
    • Client-provided sort keys fed directly into ORDER BY.
  • Safer patterns (Java/JDBC)

try (var conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PW);
     var ps = conn.prepareStatement("SELECT department FROM employees WHERE first_name = ?")) {
    ps.setString(1, firstName);
    try (var rs = ps.executeQuery()) {
        // consume results
    }
}
  • Avoid privileged statements from untrusted input

    • Never map user input to DDL/DCL; restrict to least-privilege service acounts.
  • Sorting with allow-lists

// Accept only vetted columns for ORDER BY (cannot parameterize identifiers)
var allowed = Map.of("ip", "ip", "hostname", "hostname", "mac", "mac");
var requested = request.getParameter("column");
var column = allowed.get(requested);
if (column == null) throw new IllegalArgumentException("Unsupported sort key");

var sql = "SELECT id, ip, hostname, mac FROM servers ORDER BY " + column;
try (var ps = conn.prepareStatement(sql); var rs = ps.executeQuery()) {
  // ...
}
  • Application-level protections
    • Cenrtalize query construction; prohibit ad‑hoc SQL building in controller code.
    • Employ ORM/DSLs with parameter binding; enable query logging and anomaly detection.
    • Use database accounts with no schema-alter permissions.

SQL Injection Mitigations (Implementation Notes)

  • Use try-with-resources and strict typing
try (var conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PW);
     var ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?")) {
    ps.setString(1, userName);
    try (var rs = ps.executeQuery()) {
        while (rs.next()) {
            // ...
        }
    }
} catch (SQLException e) {
    // log with structured logging, do not reveal SQL or stack traces to clients
}
  • Validate inputs before hitting the database

    • Enforce length/charset/format constraints.
    • Prefer server-side allow-lists to reject unexpected values early.
  • Defensive ORDER BY and field selection

record SortSpec(String column, boolean asc) {}

static SortSpec parseSort(HttpServletRequest req) {
    var allowedCols = Set.of("created_at", "username", "status");
    var col = req.getParameter("sort");
    var dir = req.getParameter("dir");
    if (!allowedCols.contains(col)) throw new IllegalArgumentException("bad sort");
    var asc = !"desc".equalsIgnoreCase(dir);
    return new SortSpec(col, asc);
}

Authentication and JWT

  • Signature verification
    • Reject tokens with unexpected algorithms; do not except "none".
    • Match algorithm to expected key type (e.g., HS256 with shared secret or RS256 with public key).
DecodedJWT decoded = JWT.decode(token);
if (!"HS256".equals(decoded.getAlgorithm())) {
    throw new SecurityException("Unexpected JWT alg");
}
Algorithm algo = Algorithm.HMAC256(hmacSecret);
JWTVerifier verifier = JWT.require(algo)
    .withAudience("webgoat.org")
    .acceptLeeway(2)
    .build();
verifier.verify(token);
  • Key management and the kid header
    • Do not interpolate kid values into SQL/paths.
String kid = decoded.getKeyId();
String sql = "SELECT secret FROM jwt_keys WHERE id = ?";
String secret = jdbc.queryForObject(sql, String.class, kid);
  • Operational safeguards
    • Strong secrets (≥256 bits for HMAC), rotation, and short exp.
    • Enforce audience/issuer checks; maintain allow‑listed algs per client.

Password Reset

  • Token design
    • Single-use, high-entropy, time-limited; bind to user and purpose.
SecureRandom sr = new SecureRandom();
byte[] buf = new byte[32];
sr.nextBytes(buf);
String token = Base64.getUrlEncoder().withoutPadding().encodeToString(buf);
// Persist: {userId, tokenHash, expiresAt, used=false}
  • URL construction
    • Build absolute URLs from server configuration; never trust Host/X‑Forwarded‑* headers without a vetted proxy.
    • Validate token server-side; do not rely on predictable or derived values.

XXE (XML External Entity)

  • Secure parser configuration
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
  • Prefer JSON for transport; if XML is required, enforce strict schemas and size limits.

Insecure Direct Object References (IDOR)

  • Enforce object-level authorization
Order order = orderRepo.findById(orderId)
    .orElseThrow(() -> new NotFoundException());
if (!order.getOwnerId().equals(currentUser.getId())) {
    throw new AccessDeniedException("forbidden");
}
return order;
  • Design guidelines
    • Use opaque, non-predictable identifiers where possible.
    • Apply checks consistently on every endpoint, not just views.

Missing Function-Level Access Control

  • Method-level enforcement
@RestController
@RequestMapping("/admin")
@PreAuthorize("hasAuthority('ADMIN')")
class AdminController {
  @GetMapping("/config")
  public Config view() { /* ... */ }
}
  • Validate Content-Type and accept headers strictly; do not expose alternate behaviors on the same path without authorization gates.

Cross-Site Scripting (XSS)

  • Output encoding and templating
<!-- Server-side template engine (e.g., Thymeleaf) -->
<p th:text="${cardNumber}"></p> <!-- Escaped by default -->
  • Client-side insertion
document.querySelector('#output').innerText = userInput; // never innerHTML
  • Complementary defenses: CSP, HTTPOnly cookies, input length limits.

Insecure Deserialization

  • Avoid native Java serialization for untrusted data
    • Prefer JSON/Protobuf with explicit schemas.
    • If deserialization is unavoidable, apply type filtering and sandboxing.
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("maxbytes=10240;!java.lang.Runtime;!*script*;!*");
try (var ois = new ObjectInputStream(in)) {
    ois.setObjectInputFilter(filter);
    Object obj = ois.readObject();
}
  • For JSON, disable polymorphic typing unless strictly required
ObjectMapper om = new ObjectMapper();
om.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
// Or better: avoid default typing; register concrete types only

Vulnerable Components

  • Track and patch dependencies
<!-- Maven: OWASP Dependency-Check -->
<plugin>
  <groupId>org.owasp</groupId>
  <artifactId>dependency-check-maven</artifactId>
  <version>9.0.0</version>
  <executions>
    <execution>
      <goals><goal>check</goal></goals>
    </execution>
  </executions>
</plugin>
  • Use SBOMs and CI policies to block builds with known CVEs.

Cross-Site Request Forgery (CSRF)

  • Tokenization and SameSite
http
  .csrf(csrf -> csrf
      .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
  .requiresChannel(ch -> ch.anyRequest().requiresSecure());
  • For JSON APIs
    • Require a CSRF token header from same-origin pages, or rely on SameSite=strict and double-submit cookies.
    • Validate Origin/Referer for state-changing requests.

Server-Side Request Forgery (SSRF)

  • Allow-list and network egress controls
URI uri = URI.create(userUrl);
if (!Set.of("https", "http").contains(uri.getScheme())) throw new IllegalArgumentException();
InetAddress addr = InetAddress.getByName(uri.getHost());
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress() || isPrivate(addr)) {
    throw new AccessDeniedException("internal address");
}
// perform request via hardened HTTP client with timeouts
static boolean isPrivate(InetAddress a) {
    byte[] b = a.getAddress();
    int first = b[0] & 0xFF;
    int second = b[1] & 0xFF;
    return first == 10 || (first == 172 && (second >= 16 && second <= 31)) || (first == 192 && second == 168);
}
  • Resolve DNS per request and re-check IP after redirects; deny file://, gopher://, etc.

Bypassing Front-End Restrictions (Defensive View)

  • Never trust client-side validation; validate on the server using schemas and annotations
record Registration(
  @NotBlank @Size(max = 40) String username,
  @Email String email,
  @Pattern(regexp = "^[0-9]{10}$") String phone
) {}

Client-Side Filtering

  • Treat client-side filters as UX only; enforce authorization and data shape server-side.
  • Avoid exposing internal APIs that return unrestricted data; implement pagination and field selection allow-lists.

HTML Tampering

  • Recompute sensitive fields on the server
BigDecimal serverTotal = items.stream()
    .map(i -> i.price().multiply(BigDecimal.valueOf(i.quantity())))
    .reduce(BigDecimal.ZERO, BigDecimal::add);
if (requestTotal.compareTo(serverTotal) != 0) {
    throw new IllegalStateException("mismatched total");
}

Operational Hardening Summary

  • Centralize input validation and encoding.
  • Apply RBAC checks at controller and service layers.
  • Log security-relevant events and enable rate limits.
  • Conduct dependency and container image scanning.
  • Use secure defaults (HTTP security headers, TLS-only) and enforce least privilege across the stack.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.