Skip to content

Commit

Permalink
Merge pull request #565 from Nizernizer/feature/add-validator-rule
Browse files Browse the repository at this point in the history
feature: add validator handler.
  • Loading branch information
lostsnow authored Aug 10, 2023
2 parents 1fed3dd + 2b78dae commit 5dcf8f8
Show file tree
Hide file tree
Showing 27 changed files with 319 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ private ConfigBuilder() {
Config.<Boolean>create(ConfigKey.ENABLE_LOGGER));
this.configMap.put(ConfigKey.LOGGER_LEVEL,
Config.<String>create(ConfigKey.LOGGER_LEVEL));
this.configMap.put(ConfigKey.VALIDATED_SINK,
Config.<Boolean>create(ConfigKey.VALIDATED_SINK).setDefaultValue(false));
}

public static ConfigBuilder getInstance() {
Expand Down Expand Up @@ -62,6 +64,7 @@ public void update(JSONObject config) {
updateString(config, ConfigKey.JsonKey.JSON_VERSION_HEADER_KEY);
updateBool(config, ConfigKey.JsonKey.JSON_ENABLE_LOGGER);
updateString(config, ConfigKey.JsonKey.JSON_LOGGER_LEVEL);
updateBool(config, ConfigKey.JsonKey.JSON_VALIDATED_SINK);
updateRequestDenyList(config);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public enum ConfigKey {
VERSION_HEADER_KEY,
ENABLE_LOGGER,
LOGGER_LEVEL,
VALIDATED_SINK,
;

public enum JsonKey {
Expand All @@ -18,6 +19,7 @@ public enum JsonKey {
JSON_VERSION_HEADER_KEY("version_header_name", VERSION_HEADER_KEY),
JSON_ENABLE_LOGGER("enable_log", ENABLE_LOGGER),
JSON_LOGGER_LEVEL("log_level", LOGGER_LEVEL),
JSON_VALIDATED_SINK("report_validated_sink", VALIDATED_SINK),
;

private final String key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ public class PropertyConstant {
public static final String PROPERTY_POLICY_PATH = "dongtai.policy.path";
public static final String PROPERTY_UUID_PATH = "dongtai.uuid.path";
public static final String PROPERTY_DISABLED_PLUGINS = "dongtai.disabled.plugins";
public static final String PROPERTY_DISABLED_FEATURES = "dongtai.disabled_features";
public static final String PROPERTY_DISABLED_FEATURES = "dongtai.disabled.features";
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ static Method getAsmMethod(final Class<?> clazz,
SpyDispatcher.class,
"isFirstLevelSink"
);

Method SPY$enterValidator = InnerHelper.getAsmMethod(
SpyDispatcher.class,
"enterValidator"
);

Method SPY$enterIgnoreInternal = InnerHelper.getAsmMethod(
SpyDispatcher.class,
"enterIgnoreInternal"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class ClassVisit extends AbstractClassVisitor {
new SourceAdapter(),
new PropagatorAdapter(),
new SinkAdapter(),
new ValidatorAdapter(),
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.dongtai.iast.core.bytecode.enhance.plugin.core.adapter;

import io.dongtai.iast.core.bytecode.enhance.MethodContext;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNode;
import io.dongtai.iast.core.handler.hookpoint.models.policy.ValidatorNode;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.Set;

public class ValidatorAdapter extends MethodAdapter {
/**
* @param adapter
* @param mv
* @param context
* @param policyNodes
*/
@Override
public void onMethodEnter(MethodAdviceAdapter adapter, MethodVisitor mv, MethodContext context, Set<PolicyNode> policyNodes) {
}

/**
* @param adapter
* @param mv
* @param opcode
* @param context
* @param policyNodes
*/
@Override
public void onMethodExit(MethodAdviceAdapter adapter, MethodVisitor mv, int opcode, MethodContext context, Set<PolicyNode> policyNodes) {
for (PolicyNode policyNode : policyNodes) {
if (!(policyNode instanceof ValidatorNode)) {
continue;
}

Label elseLabel = new Label();
Label endLabel = new Label();

isEnterScope(adapter);
mv.visitJumpInsn(Opcodes.IFEQ, elseLabel);

adapter.trackMethod(opcode, policyNode, true);

adapter.mark(elseLabel);
adapter.mark(endLabel);
}
}

private void isEnterScope(MethodAdviceAdapter adapter) {
adapter.invokeStatic(ASM_TYPE_SPY_HANDLER, SPY_HANDLER$getDispatcher);
adapter.invokeInterface(ASM_TYPE_SPY_DISPATCHER, SPY$enterValidator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,8 @@ public void collectDubboResponse(Object result, byte status) {
}

if (!ScopeManager.SCOPE_TRACKER.getScope(Scope.DUBBO_REQUEST).isFirst()
|| !ScopeManager.SCOPE_TRACKER.getScope(Scope.DUBBO_ENTRY).in()) {
|| !ScopeManager.SCOPE_TRACKER.getScope(Scope.DUBBO_ENTRY).in()
|| ScopeManager.SCOPE_TRACKER.getScope(Scope.HTTP_REQUEST).in()) {
return;
}

Expand Down Expand Up @@ -558,6 +559,17 @@ public void leaveSink() {
}
}

/**
* mark for enter validator entry point
*/
@Override
public boolean enterValidator() {
if (!EngineManager.isEngineRunning()) {
return false;
}
return !ScopeManager.SCOPE_TRACKER.inAgent() && ScopeManager.SCOPE_TRACKER.inEnterEntry();
}

/**
* Determines whether it is a layer 1 Sink entry
*
Expand Down Expand Up @@ -674,6 +686,9 @@ public boolean collectMethod(Object instance, Object[] parameters, Object retObj
} else if ((policyNode instanceof SinkNode)) {
SinkImpl.solveSink(event, (SinkNode) policyNode);
return true;
} else if ((policyNode instanceof ValidatorNode)) {
ValidatorImpl.solveValidator(event,(ValidatorNode)policyNode, INVOKE_ID_SEQUENCER);
return true;
}

return false;
Expand Down Expand Up @@ -731,7 +746,7 @@ public boolean traceDubboInvoke(Object instance, String url, Object invocation,
@Override
public boolean isSkipCollectDubbo(Object invocation) {
if (BlackUrlBypass.isBlackUrl()) {
Method setAttachmentMethod = null;
Method setAttachmentMethod;
try {
setAttachmentMethod = invocation.getClass().getMethod("setAttachment", String.class, String.class);
setAttachmentMethod.setAccessible(true);
Expand All @@ -746,7 +761,7 @@ public boolean isSkipCollectDubbo(Object invocation) {
@Override
public boolean isSkipCollectFeign(Object instance) {
if (BlackUrlBypass.isBlackUrl()) {
Field metadataField = null;
Field metadataField;
try {
metadataField = instance.getClass().getDeclaredField("metadata");
metadataField.setAccessible(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.dongtai.iast.core.handler.context.ContextManager;
import io.dongtai.iast.core.handler.hookpoint.IastClassLoader;
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNodeType;
import io.dongtai.iast.core.handler.hookpoint.models.policy.SourceNode;
import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition;
import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRange;
Expand Down Expand Up @@ -178,6 +179,7 @@ public static void collectDubboRequestSource(Object handler, Object invocation,

int invokeId = invokeIdSequencer.getAndIncrement();
event.setInvokeId(invokeId);
event.setPolicyType(PolicyNodeType.SOURCE.getName());

event.source = true;
event.setCallStacks(StackUtils.createCallStack(4));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.dongtai.iast.core.EngineManager;
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNodeType;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PropagatorNode;
import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition;
import io.dongtai.iast.core.handler.hookpoint.models.taint.range.*;
Expand Down Expand Up @@ -63,6 +64,7 @@ private static void addPropagator(PropagatorNode propagatorNode, MethodEvent eve
event.setCallStacks(StackUtils.createCallStack(6));
int invokeId = invokeIdSequencer.getAndIncrement();
event.setInvokeId(invokeId);
event.setPolicyType(PolicyNodeType.PROPAGATOR.getName());
EngineManager.TRACK_MAP.get().put(invokeId, event);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.dongtai.iast.core.EngineManager;
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNodeType;
import io.dongtai.iast.core.handler.hookpoint.models.policy.SourceNode;
import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition;
import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRangesBuilder;
Expand Down Expand Up @@ -37,6 +38,7 @@ public static void solveSource(MethodEvent event, SourceNode sourceNode, AtomicI

int invokeId = invokeIdSequencer.getAndIncrement();
event.setInvokeId(invokeId);
event.setPolicyType(PolicyNodeType.SOURCE.getName());

boolean valid = trackTarget(event, sourceNode);
if (!valid) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package io.dongtai.iast.core.handler.hookpoint.controller.impl;

import io.dongtai.iast.core.EngineManager;
import io.dongtai.iast.core.handler.hookpoint.models.MethodEvent;
import io.dongtai.iast.core.handler.hookpoint.models.policy.PolicyNodeType;
import io.dongtai.iast.core.handler.hookpoint.models.policy.TaintPosition;
import io.dongtai.iast.core.handler.hookpoint.models.policy.ValidatorNode;
import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRange;
import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRanges;
import io.dongtai.iast.core.handler.hookpoint.models.taint.range.TaintRangesBuilder;
import io.dongtai.iast.core.handler.hookpoint.models.taint.tag.TaintTag;
import io.dongtai.iast.core.utils.StackUtils;
import io.dongtai.iast.core.utils.TaintPoolUtils;

import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import static io.dongtai.iast.core.utils.TaintPoolUtils.getStringHash;

public class ValidatorImpl {

/**
* 处理 Validator 点的事件
*
* @param event Validator 点事件
*/
public static void solveValidator(MethodEvent event, ValidatorNode validatorNode, AtomicInteger invokeIdSequencer) {
if (EngineManager.TAINT_HASH_CODES.isEmpty()) {
return;
}
Set<TaintPosition> sources = validatorNode.getSources();
if (sources.isEmpty()) {
return;
}

for (TaintPosition position : sources) {
Long hash = null;
Integer len = null;
if (position.isObject()) {
if (TaintPoolUtils.isNotEmpty(event.objectInstance)
&& TaintPoolUtils.isAllowTaintType(event.objectInstance)
&& TaintPoolUtils.poolContains(event.objectInstance, event)) {
hash = getStringHash(event.objectInstance);
len = TaintRangesBuilder.getLength(event.objectInstance);
event.setObjectValue(event.objectInstance, true);
}
} else if (position.isParameter()) {
int parameterIndex = position.getParameterIndex();
if (parameterIndex >= event.parameterInstances.length) {
continue;
}
Object parameter = event.parameterInstances[parameterIndex];
if (TaintPoolUtils.isNotEmpty(parameter)
&& TaintPoolUtils.isAllowTaintType(parameter)
&& TaintPoolUtils.poolContains(parameter, event)) {
hash = getStringHash(parameter);
len = TaintRangesBuilder.getLength(parameter);
event.addParameterValue(parameterIndex, parameter, true);
}
} else return;

if (null != len && null != hash){
TaintRanges tr = new TaintRanges(new TaintRange(TaintTag.VALIDATED.getKey(), 0, len));
if (validatorNode.hasTags()) {
String[] tags = validatorNode.getTags();
for (String tag : tags) {
tr.add(new TaintRange(tag, 0, len));
}
}
event.sourceRanges.add(new MethodEvent.MethodEventTargetRange(hash, tr));
TaintRanges taintRanges = EngineManager.TAINT_RANGES_POOL.get().get(hash);
if (null == taintRanges){
EngineManager.TAINT_RANGES_POOL.add(hash, tr);
}else {
taintRanges.addAll(tr);
}
}else return;
}

event.source = false;
event.setCallStacks(StackUtils.createCallStack(4));
event.setTaintPositions(validatorNode.getSources(), null);

int invokeId = invokeIdSequencer.getAndIncrement();
event.setInvokeId(invokeId);
event.setPolicyType(PolicyNodeType.VALIDATOR.getName());
EngineManager.TRACK_MAP.addTrackMethod(invokeId, event);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public static JSONObject toJson(MethodEvent event) {
List<String> targetPositions = new ArrayList<String>();

value.put("invokeId", event.getInvokeId());
value.put("policyType", event.getPolicyType());
value.put("source", event.isSource());
value.put("originClassName", event.getOriginClassName());
value.put("className", event.getMatchedClassName());
Expand Down Expand Up @@ -167,6 +168,14 @@ public static JSONObject toJson(MethodEvent event) {
}
}

if (event.sourceRanges.size() > 0) {
JSONArray tr = new JSONArray();
value.put("sourceRange", tr);
for (MethodEvent.MethodEventTargetRange range : event.sourceRanges) {
tr.add(range.toJson());
}
}

if (event.sourceTypes != null && event.sourceTypes.size() > 0) {
JSONArray st = new JSONArray();
value.put("sourceType", st);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public class MethodEvent {
*/
private int invokeId;

/**
* policy type
*/
private String policyType;

/**
* is source policy node
*/
Expand Down Expand Up @@ -88,6 +93,8 @@ public class MethodEvent {

public List<MethodEventTargetRange> targetRanges = new ArrayList<MethodEventTargetRange>();

public List<MethodEventTargetRange> sourceRanges = new ArrayList<MethodEventTargetRange>();

public List<MethodEventSourceType> sourceTypes;

private StackTraceElement callStack;
Expand Down Expand Up @@ -172,6 +179,14 @@ public void setInvokeId(int invokeId) {
this.invokeId = invokeId;
}

public String getPolicyType() {
return policyType;
}

public void setPolicyType(String policyType) {
this.policyType = policyType;
}

public boolean isSource() {
return source;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class Policy {
private final List<SourceNode> sources = new ArrayList<SourceNode>();
private final List<PropagatorNode> propagators = new ArrayList<PropagatorNode>();
private final List<SinkNode> sinks = new ArrayList<SinkNode>();
private final List<ValidatorNode> validators = new ArrayList<ValidatorNode>();
private final Map<String, PolicyNode> policyNodesMap = new HashMap<String, PolicyNode>();
private final Set<String> classHooks = new HashSet<String>();
private final Set<String> ancestorClassHooks = new HashSet<String>();
Expand Down Expand Up @@ -43,6 +44,11 @@ public void addSink(SinkNode sink) {
addPolicyNode(sink);
}

public void addValidator(ValidatorNode validator) {
this.validators.add(validator);
addPolicyNode(validator);
}

public PolicyNode getPolicyNode(String policyKey) {
return this.policyNodesMap.get(policyKey);
}
Expand Down
Loading

0 comments on commit 5dcf8f8

Please sign in to comment.