Skip to content

Conversation

@kevin-montrose
Copy link
Contributor

This is a proposal (and thus a draft PR) to add a Condition to behaviors that allows control of whether a behavior's InjectableArguments apply, akin to the Condition on attributes from #127 .

Currently, at least as I understand, it is possible to conditionally control what taint is applied to a returned value (either absolutely, or via arguments). InjectableArguments are unconditionally considered.

The motivating use here are RedirectAction returning methods in the Stack Overflow codebase which default to disallowing external domains, but have a parameter that when set allows external targets. Calls are therefore vulnerable to an open redirect injection only when the parameter is set. A minimal example of this is in the included test.

This also pulls in the commits from #134 , since that was needed to test successfully against the full Stack Overflow code base.

@kevin-montrose
Copy link
Contributor Author

@JarLob I'll move this to be against master too, though probably not until Monday (need to test it against actual Stack Overflow, and that's tricky on the weekend). If you have any comments before then, I can address them as part of moving these commits over as well.

Copy link
Contributor

@JarLob JarLob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

if (!(kv.Key is int) && !(kv.Key is string str && int.TryParse(str, out _)))
throw new Exception("Condition key must be an argument index");

var argIx = int.Parse(""+kv.Key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is odd to convert the key to string and back in case it is int. I would rather have a switch on is.

var argIx = int.Parse(""+kv.Key);
if(argIx < 0)
throw new Exception("Condition key must be an argument index >= 0");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra empty line

[DataRow("Injectable", "\"\", userProvided", false)]
[DataRow("Injectable", "userProvided, \"\"", true)]
[DataRow("Injectable", "\"\", \"\"", false)]
[DataRow("Injectable", "userProvided, userProvided", true)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You destroyed my beautiful formatting...

if (e.InnerException != null)
Logger.Log($"{e.InnerException.Message}");
Logger.Log($"\n{e.StackTrace}", false);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather add the empty line before Logger.Log($"\n{e.StackTrace}", false);

: null;

var behaviorApplies = behavior != null && BehaviorApplies(behavior.AppliesUnderCondition, methodSymbol, argList?.Arguments, state);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra empty line

if (destIx >= vals.Length)
return false;

vals[destIx] = val.Value?.ToString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again for performance it is better to avoid string allocation. Could the object be used instead?

if (val.HasValue)
{
if (destIx >= vals.Length)
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does it happen? With params? Could you add a test? If this is impossible situation I would rather throw.


foreach (var kv in condition)
{
var ix = int.Parse((string)kv.Key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, remember about optimized internal configuration structure. This can be done only once during config loading.

var ix = int.Parse((string)kv.Key);

if (ix >= vals.Length)
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid configuration? I would throw and let the user know his config is wrong.

if (codeVal == null)
return false;

if (!codeVal.Equals(expectedVal.ToString()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compare objects instead?

kevin-montrose added a commit to kevin-montrose/security-code-scan that referenced this pull request Aug 19, 2019
@kevin-montrose
Copy link
Contributor Author

Closing this in favor of #137, which is against master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants