Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions java/src/security/CWE-295/InsecureJdbcCertificateValidation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# JDBC connection disables TLS certificate validation

A JDBC URL containing `trustServerCertificate=true` makes the driver accept any server certificate. Even when the URL also sets `encrypt=true`, the channel is then encrypted but unauthenticated, so a man-in-the-middle can present its own certificate, impersonate the database, and read or modify all traffic, including credentials.

## Recommendation
Remove `trustServerCertificate=true` and let the driver validate the server certificate against a trusted certificate authority. If the database uses a private CA, import that CA into the client trust store rather than disabling validation.

## Example
The following example builds a SQL Server JDBC URL that disables certificate validation.

```java
// BAD: trustServerCertificate=true accepts any certificate (MITM risk).
private static final String JDBC_URL =
"jdbc:sqlserver://db01.corp.example.com:1433;databaseName=App;"
+ "encrypt=true;trustServerCertificate=true;loginTimeout=5";

try (Connection c = DriverManager.getConnection(JDBC_URL, user, password)) {
// ...
}
```

Use `encrypt=true;trustServerCertificate=false` and trust the server certificate through the client trust store.

## References
* Microsoft: [Connecting with encryption (JDBC driver for SQL Server)](https://learn.microsoft.com/en-us/sql/connect/jdbc/connecting-with-ssl-encryption).
* Common Weakness Enumeration: [CWE-295](https://cwe.mitre.org/data/definitions/295.html).
53 changes: 53 additions & 0 deletions java/src/security/CWE-295/InsecureJdbcCertificateValidation.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @name JDBC connection disables TLS certificate validation
* @description A JDBC URL containing `trustServerCertificate=true` makes the driver
* accept any server certificate. Even with `encrypt=true` the channel
* is then encrypted but unauthenticated, letting a man-in-the-middle
* impersonate the database.
* @kind problem
* @problem.severity warning
* @security-severity 7.5
* @precision medium
* @id githubsecuritylab/java/jdbc-insecure-certificate
* @tags security
* external/cwe/cwe-295
*/

import java

/**
* Holds if `e` evaluates to the constant string `v`, resolving a single field
* indirection and constant string concatenation.
*/
predicate constantStringValue(Expr e, string v) {
v = e.(CompileTimeConstantExpr).getStringValue()
or
exists(Variable var |
e = var.getAnAccess() and
v = var.getAnAssignedValue().(CompileTimeConstantExpr).getStringValue()
)
}

/** A call that opens or configures a JDBC connection from a URL argument. */
class JdbcUrlSink extends MethodCall {
Expr urlArg;

JdbcUrlSink() {
this.getMethod().hasName("getConnection") and
this.getMethod().getDeclaringType().hasQualifiedName("java.sql", "DriverManager") and
urlArg = this.getArgument(0)
or
this.getMethod().hasName(["setUrl", "setJdbcUrl"]) and
this.getQualifier().getType().(RefType).getName().matches(["%DataSource%", "%Config%"]) and
urlArg = this.getArgument(0)
}

Expr getUrlArg() { result = urlArg }
}

from JdbcUrlSink sink, string url
where
constantStringValue(sink.getUrlArg(), url) and
url.regexpMatch("(?i).*trustservercertificate\\s*=\\s*true.*")
select sink,
"JDBC connection uses 'trustServerCertificate=true', disabling certificate validation (MITM risk)."
28 changes: 28 additions & 0 deletions java/src/security/CWE-319/CleartextLdapUrl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Cleartext LDAP URL

Configuring an LDAP context source with an `ldap://` URL transmits bind credentials and directory data over an unencrypted channel. An attacker positioned on the network can intercept the service-account password and the contents of every directory query and response.

## Recommendation
Use `ldaps://` (LDAP over TLS) or enable STARTTLS so that the connection to the directory server is encrypted and authenticated. Store the bind password outside source control (for example in a secret manager or environment variable).

## Example
The following example configures a Spring `LdapContextSource` with a cleartext `ldap://` URL, so the bind credentials cross the network in the clear.

```java
@Bean
public LdapContextSource ldapContextSource() {
LdapContextSource ctx = new LdapContextSource();
// BAD: cleartext ldap:// transmits the bind password unencrypted.
ctx.setUrl("ldap://ldap.corp.example.com:389");
ctx.setUserDn("cn=svc-app,ou=ServiceAccounts,dc=corp,dc=example,dc=com");
ctx.setPassword(System.getenv("LDAP_PASSWORD"));
ctx.afterPropertiesSet();
return ctx;
}
```

Use `ldaps://ldap.corp.example.com:636` instead.

## References
* OWASP: [Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html).
* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).
47 changes: 47 additions & 0 deletions java/src/security/CWE-319/CleartextLdapUrl.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @name Cleartext LDAP URL
* @description Configuring an LDAP context source with an `ldap://` URL transmits
* bind credentials and directory data over an unencrypted channel,
* allowing them to be intercepted. Use `ldaps://` or STARTTLS instead.
* @kind problem
* @problem.severity warning
* @security-severity 7.5
* @precision medium
* @id githubsecuritylab/java/cleartext-ldap-url
* @tags security
* external/cwe/cwe-319
*/

import java

/**
* Holds if `e` evaluates to the constant string `v`, resolving a single field
* indirection (e.g. a `private static final String` constant).
*/
predicate constantStringValue(Expr e, string v) {
v = e.(CompileTimeConstantExpr).getStringValue()
or
exists(Variable var |
e = var.getAnAccess() and
v = var.getAnAssignedValue().(CompileTimeConstantExpr).getStringValue()
)
}

/** A call that configures the URL of an LDAP/JNDI context source. */
class LdapUrlSink extends MethodCall {
Expr urlArg;

LdapUrlSink() {
this.getMethod().hasName(["setUrl", "setUrls", "setProviderUrl"]) and
this.getQualifier().getType().(RefType).getName().matches("%ContextSource%") and
urlArg = this.getArgument(0)
}
Comment on lines +34 to +38

Expr getUrlArg() { result = urlArg }
}

from LdapUrlSink sink, string url
where
constantStringValue(sink.getUrlArg(), url) and
url.regexpMatch("(?i)ldap://.*")
select sink, "LDAP context configured with cleartext URL '" + url + "'; use ldaps:// or STARTTLS."
Comment on lines +43 to +47
27 changes: 27 additions & 0 deletions java/src/security/CWE-598/CredentialsInOutboundUrl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Credentials transmitted in outbound request URL

Embedding a password or other secret in the URL of an outbound HTTP request exposes the credential in server logs, proxy logs, and browser history. When the request is sent over `http://` the credential also crosses the network in cleartext, where it can be intercepted.

## Recommendation
Send credentials in an `Authorization` header or a request body over a TLS-protected connection (`https://`), not as URL query parameters. Avoid logging full request URLs that contain secrets.

## Example
The following example concatenates a password into the query string of a request issued with a Spring `RestTemplate`.

```java
public String fetchReport(String reportName) {
// BAD: the password is placed in the request URL.
String url = props.getUrl()
+ "/Render?report=" + reportName
+ "&user=" + props.getUsername()
+ "&password=" + props.getPassword();
return restTemplate.getForObject(url, String.class);
}
```

Send the credentials in a header instead, for example via `HttpHeaders.setBasicAuth(...)` over `https://`.

## References
* OWASP: [Information exposure through query strings in URL](https://owasp.org/www-community/vulnerabilities/Information_exposure_through_query_strings_in_url).
* Common Weakness Enumeration: [CWE-598](https://cwe.mitre.org/data/definitions/598.html).
* Common Weakness Enumeration: [CWE-319](https://cwe.mitre.org/data/definitions/319.html).
64 changes: 64 additions & 0 deletions java/src/security/CWE-598/CredentialsInOutboundUrl.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @name Credentials transmitted in outbound request URL
* @description Embedding a password or secret in the URL of an outbound HTTP
* request exposes the credential in server logs, proxies and
* browser history, and over `http://` leaks it in cleartext on the
* wire. Send credentials in headers or a request body over TLS.
* @kind path-problem
* @problem.severity warning
* @security-severity 7.5
* @precision medium
* @id githubsecuritylab/java/credentials-in-outbound-url
* @tags security
* external/cwe/cwe-598
* external/cwe/cwe-319
*/

import java
import semmle.code.java.dataflow.TaintTracking
import CredentialsInUrlFlow::PathGraph

/** A getter whose name suggests it returns a credential or secret. */
class CredentialGetter extends MethodCall {
CredentialGetter() {
this.getMethod()
.getName()
.regexpMatch("(?i)get(pass(word|wd)?|secret|credential|apikey|api_?key|token).*")
}
}

/** The URL argument of an outbound HTTP client request. */
class OutboundUrlArg extends Expr {
OutboundUrlArg() {
exists(MethodCall ma |
(
ma.getMethod()
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.springframework.web.client", "RestOperations")
or
ma.getMethod()
.hasName([
"getForObject", "getForEntity", "postForObject", "postForEntity", "put", "delete",
"exchange", "execute"
]) and
ma.getQualifier().getType().(RefType).getName().matches("%RestTemplate%")
) and
this = ma.getArgument(0)
)
}
}

module CredentialsInUrlConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialGetter }

predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof OutboundUrlArg }
}

module CredentialsInUrlFlow = TaintTracking::Global<CredentialsInUrlConfig>;

from CredentialsInUrlFlow::PathNode source, CredentialsInUrlFlow::PathNode sink
where CredentialsInUrlFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"Credential from $@ is concatenated into the URL of an outbound HTTP request.", source.getNode(),
"this getter"
34 changes: 34 additions & 0 deletions java/src/security/CWE-639/InsecureDirectObjectReference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Insecure direct object reference

A web action that operates on a resource identified by user input, without checking that the current user is authorized to act on that specific resource, allows an attacker to access or modify arbitrary objects by changing the identifier.

This query is the Java analogue of the C# query `cs/web/insecure-direct-object-reference`. It flags a state-changing Spring controller action that takes an id-like parameter but performs no user or session check and carries no method-security annotation.

## Recommendation
Add an authorization check that ties the request to the authenticated user before acting on the resource. This can be a method-security annotation such as `@PreAuthorize` or `@PostAuthorize`, an explicit ownership check against the current user or session, or a query scoped to the caller.

## Example
The following example deletes a record identified by a path variable without verifying that the caller owns it.

```java
@DeleteMapping("/{id}")
public void deleteStatement(@PathVariable long id) {
// BAD: no check that the current user may delete record `id`.
service.delete(id);
}
```

Restrict the action with an authorization check, for example:

```java
@DeleteMapping("/{id}")
@PreAuthorize("@statementAccess.isOwner(#id, authentication.name)")
public void deleteStatement(@PathVariable long id) {
service.delete(id);
}
```

## References
* OWASP: [Insecure Direct Object Reference Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html).
* OWASP Top 10: [A01:2021 Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/).
* Common Weakness Enumeration: [CWE-639](https://cwe.mitre.org/data/definitions/639.html).
Loading
Loading