Skip to content

Java: Checking if map has specific key #160

Answered
46d ago
· 2 replies
Answered
Copy link

@h0ng10 h0ng10

Hello everyone

I just got started using CodeQL and currently try to write a query for the following case:
I have a Java Map (Map<String,Object>) which gets passed to a critical function. I want to make sure that the map contains an entry for the key "forceAuthentication".

Here my bloody beginner attempt:

import java
import semmle.code.java.Maps
import semmle.code.java.dataflow.DataFlow

class SettingsFactoryMethodAccess extends MethodAccess {
    SettingsFactoryMethodAccess() {
        getCallee().getDeclaringType().getName() = "SettingsFactory"
        and getCallee().getDeclaringType().getPackage().getName() = "my.little.library"
        and getMethod().getName() = "newSettings"
    }
}

from FreshMap map, MapMethod method, MapPutCall put, SettingsFactoryMethodAccess settings
    where 
    method.getReceiverKeyType().getName() = "String" and 
    method.getReceiverValueType().getName() = "Object" and 
    not put.getKey().toString() = "forceAuthentication" and
    DataFlow::localFlow(DataFlow::exprNode(map),DataFlow::exprNode(settings.getArgument(0)))

select map, settings

The local data flow seems to work, however I'm stuck when it comes to do the actual check if the key is set. Is this the right approach or do I need to implement this as a guard?

Thank you for your help!

Replies

Answer selected by xcorail

For the next time (not specific to you but in general, when I'm seeing such questions here) it would be great if you could include a sample project that is accessible on lgtm.com.
Otherwise no one can easily test your query.

Here is a (untested!) query that should work.
It looks for flow from any Map to your sensitive function.
If there is a call that puts something into forceAuthentication we consider the flow safe.
Note that this is not 100% correct since it would be possible that someone clears the map afterwards.
We would still consider this safe

/**
 * @kind path-problem
 * @id foo
 */

import java
import semmle.code.java.Maps
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.DataFlow2
import DataFlow::PathGraph

predicate hasForceAuthentication(Expr e) {
  exists(ForceAuthenticationKeyConfig conf | conf.hasFlow(_, DataFlow2::exprNode(e)))
}

class ForceAuthenticationKeyConfig extends DataFlow2::Configuration {
  ForceAuthenticationKeyConfig() { this = "ForceAuthenticationKeyConfig" }

  override predicate isSource(DataFlow2::Node src) {
    src.asExpr().(CompileTimeConstantExpr).getStringValue() = "forceAuthentication"
  }

  override predicate isSink(DataFlow2::Node srce) { any() }
}

class MapWitForceAuthentication extends Expr {
  MapWitForceAuthentication() {
    exists(MapPutCall put | hasForceAuthentication(put.getKey()) |
      put.getQualifier() = this and
      put.getMethod().(MapMethod).getReceiverKeyType().getName() = "String" and
      put.getMethod().(MapMethod).getReceiverValueType().getName() = "Object"
    )
  }
}

class UncheckedMapToSensitiveFunctionConfig extends DataFlow::Configuration {
  UncheckedMapToSensitiveFunctionConfig() { this = "UncheckedMapToSensitiveFunctionConfig" }

  override predicate isSource(DataFlow::Node src) { src.asExpr().getType() instanceof MapType }

  override predicate isSink(DataFlow::Node sink) {
    exists(SettingsFactoryMethodAccess ma | ma.getAnArgument() = sink.asExpr())
  }

  override predicate isBarrier(DataFlow::Node barrier) {
    exists(MapWitForceAuthentication map | map = barrier.asExpr())
  }
}

class SettingsFactoryMethodAccess extends MethodAccess {
  SettingsFactoryMethodAccess() {
    getCallee().getDeclaringType().getName() = "SettingsFactory" and
    getCallee().getDeclaringType().getPackage().getName() = "my.little.library" and
    getMethod().getName() = "newSettings"
  }
}

from UncheckedMapToSensitiveFunctionConfig conf, DataFlow::PathNode src, DataFlow::PathNode sink
where conf.hasFlowPath(src, sink)
select sink, src, sink, "Oh no"
@h0ng10

Hello

@intrigus-lgtm that looks really good, thank you very much. Sorry for not providing a test project, i will keep that in mind the next time.
I will have a look at this over the weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants
Beta
You can’t perform that action at this time.