зеркало из https://github.com/github/codeql-go.git
Improve BadRedirectCheck query
We now look for a path from the variable being checked to a redirect. Additionally, several sources of false positives have been eliminated, and a model of relevant parts of the Macaron framework has been added.
This commit is contained in:
Родитель
dd4f1ca70b
Коммит
cd1d699208
|
@ -0,0 +1,17 @@
|
|||
# Improvements to Go analysis
|
||||
|
||||
## General improvements
|
||||
|
||||
* A model for the Macaron HTTP library's `Context.Redirect` function was added.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------------------------|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Bad redirect check (`go/bad-redirect-check`) | More accurate results | The query now checks for a use of the value checked by the result in a redirect call, and no longer uses names as a heuristic for whether the checked value is a URL. |
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[[ condition: enterprise-only ]]
|
||||
|
||||
# Improvements to Go analysis
|
||||
|
||||
## Changes to code extraction
|
|
@ -3,8 +3,8 @@
|
|||
* @description A redirect check that checks for a leading slash but not two
|
||||
* leading slashes or a leading slash followed by a backslash is
|
||||
* incomplete.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id go/bad-redirect-check
|
||||
* @tags security
|
||||
* external/cwe/cwe-601
|
||||
|
@ -12,6 +12,8 @@
|
|||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.OpenUrlRedirectCustomizations
|
||||
import DataFlow::PathGraph
|
||||
|
||||
StringOps::HasPrefix checkForLeadingSlash(SsaWithFields v) {
|
||||
exists(DataFlow::Node substr |
|
||||
|
@ -21,43 +23,163 @@ StringOps::HasPrefix checkForLeadingSlash(SsaWithFields v) {
|
|||
)
|
||||
}
|
||||
|
||||
DataFlow::Node checkForSecondSlash(SsaWithFields v) {
|
||||
exists(StringOps::HasPrefix hp | result = hp and hp.getBaseString() = v.getAUse() |
|
||||
predicate isCheckedForSecondSlash(SsaWithFields v) {
|
||||
exists(StringOps::HasPrefix hp | hp.getBaseString() = v.getAUse() |
|
||||
hp.getSubstring().getStringValue() = "//"
|
||||
)
|
||||
or
|
||||
exists(DataFlow::EqualityTestNode eq, DataFlow::Node slash, DataFlow::ElementReadNode er |
|
||||
result = eq
|
||||
|
|
||||
slash.getStringValue() = "/" and
|
||||
er.getBase() = v.getAUse() and
|
||||
er.getIndex().getIntValue() = 1 and
|
||||
eq.eq(_, er, slash)
|
||||
)
|
||||
or
|
||||
// a call to path.Clean will strip away multiple leading slashes
|
||||
isCleaned(v.getAUse())
|
||||
}
|
||||
|
||||
DataFlow::Node checkForSecondBackslash(SsaWithFields v) {
|
||||
exists(StringOps::HasPrefix hp | result = hp and hp.getBaseString() = v.getAUse() |
|
||||
/**
|
||||
* Holds if `nd` is the result of a call to `path.Clean`, or flows into the first argument
|
||||
* of such a call, possibly inter-procedurally.
|
||||
*/
|
||||
predicate isCleaned(DataFlow::Node nd) {
|
||||
exists(Function clean | clean.hasQualifiedName("path", "Clean") |
|
||||
nd = clean.getACall()
|
||||
or
|
||||
nd = clean.getACall().getArgument(0)
|
||||
)
|
||||
or
|
||||
isCleaned(nd.getAPredecessor())
|
||||
or
|
||||
exists(FuncDef f, FunctionInput inp | nd = inp.getExitNode(f) |
|
||||
forex(DataFlow::CallNode call | call.getACallee() = f | isCleaned(inp.getEntryNode(call)))
|
||||
)
|
||||
}
|
||||
|
||||
predicate isCheckedForSecondBackslash(SsaWithFields v) {
|
||||
exists(StringOps::HasPrefix hp | hp.getBaseString() = v.getAUse() |
|
||||
hp.getSubstring().getStringValue() = "/\\"
|
||||
)
|
||||
or
|
||||
exists(DataFlow::EqualityTestNode eq, DataFlow::Node slash, DataFlow::ElementReadNode er |
|
||||
result = eq
|
||||
|
|
||||
slash.getStringValue() = "\\" and
|
||||
er.getBase() = v.getAUse() and
|
||||
er.getIndex().getIntValue() = 1 and
|
||||
eq.eq(_, er, slash)
|
||||
)
|
||||
or
|
||||
// if this variable comes from or is a net/url.URL.Path, backslashes are most likely sanitized,
|
||||
// as the parse functions turn them into "%5C"
|
||||
urlPath(v.getAUse())
|
||||
}
|
||||
|
||||
from DataFlow::Node node, SsaWithFields v
|
||||
/**
|
||||
* Holds if `nd` derives its value from the field `url.URL.Path`, possibly inter-procedurally.
|
||||
*/
|
||||
predicate urlPath(DataFlow::Node nd) {
|
||||
exists(Field f |
|
||||
f.hasQualifiedName("net/url", "URL", "Path") and
|
||||
nd = f.getARead()
|
||||
)
|
||||
or
|
||||
urlPath(nd.getAPredecessor())
|
||||
or
|
||||
exists(FuncDef f, FunctionInput inp | nd = inp.getExitNode(f) |
|
||||
forex(DataFlow::CallNode call | call.getACallee() = f | urlPath(inp.getEntryNode(call)))
|
||||
)
|
||||
}
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "BadRedirectCheck" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.isSource(source, _) }
|
||||
|
||||
/**
|
||||
* Holds if `source` is the first node that flows into a use of a variable that is checked by a
|
||||
* bad redirect check `check`..
|
||||
*/
|
||||
predicate isSource(DataFlow::Node source, DataFlow::Node check) {
|
||||
exists(SsaWithFields v |
|
||||
DataFlow::localFlow(source, v.getAUse()) and
|
||||
not exists(source.getAPredecessor()) and
|
||||
isBadRedirectCheckOrWrapper(check, v)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// this is very over-approximate, because most filtering is done by the isSource predicate
|
||||
exists(Write w | w.writesField(succ, _, pred))
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
// assume this value is safe if something is prepended to it.
|
||||
exists(StringOps::Concatenation conc, int i, int j | i < j |
|
||||
node = conc.getOperand(j) and
|
||||
exists(conc.getOperand(i))
|
||||
)
|
||||
or
|
||||
exists(DataFlow::CallNode call, int i | call.getTarget().hasQualifiedName("path", "Join") |
|
||||
i > 0 and node = call.getArgument(i)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof OpenUrlRedirect::Sink }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds there is a check `check` that is a bad redirect check, and `v` is either
|
||||
* checked directly by `check` or checked by a function that contains `check`.
|
||||
*/
|
||||
predicate isBadRedirectCheckOrWrapper(DataFlow::Node check, SsaWithFields v) {
|
||||
isBadRedirectCheck(check, v)
|
||||
or
|
||||
exists(DataFlow::CallNode call, FuncDef f, FunctionInput input |
|
||||
call = f.getACall() and
|
||||
input.getEntryNode(call) = v.getAUse() and
|
||||
isBadRedirectCheckWrapper(check, f, input)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an SSA-with-fields variable that is similar to `v` in the sense that it has the same
|
||||
* root variable and the same sequence of field accesses.
|
||||
*/
|
||||
SsaWithFields similar(SsaWithFields v) {
|
||||
result.getBaseVariable().getSourceVariable() = v.getBaseVariable().getSourceVariable() and
|
||||
result.getQualifiedName() = v.getQualifiedName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `check` checks that `v` has a leading slash, but not whether it has another slash or a
|
||||
* backslash in its second position.
|
||||
*/
|
||||
predicate isBadRedirectCheck(DataFlow::Node check, SsaWithFields v) {
|
||||
// a check for a leading slash
|
||||
check = checkForLeadingSlash(v) and
|
||||
// where there does not exist a check for both a second slash and a second backslash
|
||||
// (we allow those checks to be on variables that are most likely equivalent to `v`
|
||||
// to rule out false positives due to minor variations in data flow)
|
||||
not (
|
||||
isCheckedForSecondSlash(similar(v)) and
|
||||
isCheckedForSecondBackslash(similar(v))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` contains a bad redirect check `check`, that checks the parameter `input`.
|
||||
*/
|
||||
predicate isBadRedirectCheckWrapper(DataFlow::Node check, FuncDef f, FunctionInput input) {
|
||||
exists(SsaWithFields v |
|
||||
v.getAUse().getAPredecessor*() = input.getExitNode(f) and
|
||||
isBadRedirectCheck(check, v)
|
||||
)
|
||||
}
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node check
|
||||
where
|
||||
// there is a check for a leading slash
|
||||
node = checkForLeadingSlash(v) and
|
||||
// but not a check for both a second slash and a second backslash
|
||||
not (exists(checkForSecondSlash(v)) and exists(checkForSecondBackslash(v))) and
|
||||
v.getQualifiedName().regexpMatch("(?i).*url.*|.*redir.*|.*target.*")
|
||||
select node,
|
||||
"This expression checks '$@' for a leading slash but checks do not exist for both '/' and '\\' in the second position.",
|
||||
v, v.getQualifiedName()
|
||||
cfg.isSource(source.getNode(), check) and
|
||||
cfg.hasFlowPath(source, sink)
|
||||
select check, source, sink,
|
||||
"This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position.",
|
||||
source.getNode(), "this value", sink.getNode(), "redirect"
|
||||
|
|
|
@ -25,6 +25,7 @@ import semmle.go.dataflow.GlobalValueNumbering
|
|||
import semmle.go.dataflow.TaintTracking
|
||||
import semmle.go.dataflow.SSA
|
||||
import semmle.go.frameworks.HTTP
|
||||
import semmle.go.frameworks.Macaron
|
||||
import semmle.go.frameworks.SystemCommandExecutors
|
||||
import semmle.go.frameworks.SQL
|
||||
import semmle.go.frameworks.XPath
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Provides classes for working with concepts relating to the Macaron web framework
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
private module Macaron {
|
||||
private class Context extends HTTP::ResponseWriter::Range {
|
||||
Context() {
|
||||
exists(Method m | m.hasQualifiedName("gopkg.in/macaron.v1", "Context", "Redirect") |
|
||||
m = this.getType().getMethod("Redirect")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class RedirectCall extends HTTP::Redirect::Range, DataFlow::MethodCallNode {
|
||||
RedirectCall() {
|
||||
this.getTarget().hasQualifiedName("gopkg.in/macaron.v1", "Context", "Redirect")
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = this.getArgument(0) }
|
||||
|
||||
override HTTP::ResponseWriter getResponseWriter() { result.getARead() = this.getReceiver() }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
| main.go:15:2:15:25 | call to Redirect | main.go:14:12:14:14 | ctx |
|
||||
| main.go:19:2:19:25 | call to Redirect | main.go:18:13:18:15 | ctx |
|
|
@ -0,0 +1,4 @@
|
|||
import go
|
||||
|
||||
from HTTP::Redirect redir
|
||||
select redir, redir.getResponseWriter()
|
|
@ -0,0 +1,5 @@
|
|||
module codeql-go-tests/frameworks/macaron
|
||||
|
||||
go 1.14
|
||||
|
||||
require gopkg.in/macaron.v1 v1.3.5
|
|
@ -0,0 +1,23 @@
|
|||
package main
|
||||
|
||||
//go:generate depstubber -vendor gopkg.in/macaron.v1 Context
|
||||
|
||||
import (
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
type EmbeddedContext struct {
|
||||
*macaron.Context
|
||||
foo string
|
||||
}
|
||||
|
||||
func redir(ctx *macaron.Context) {
|
||||
ctx.Redirect("/example")
|
||||
}
|
||||
|
||||
func redir1(ctx *EmbeddedContext) {
|
||||
ctx.Redirect("/example")
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
191
ql/test/library-tests/semmle/go/frameworks/Macaron/vendor/gopkg.in/macaron.v1/LICENSE
сгенерированный
поставляемый
Normal file
191
ql/test/library-tests/semmle/go/frameworks/Macaron/vendor/gopkg.in/macaron.v1/LICENSE
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,191 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright 2014 The Macaron Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
580
ql/test/library-tests/semmle/go/frameworks/Macaron/vendor/gopkg.in/macaron.v1/stub.go
сгенерированный
поставляемый
Normal file
580
ql/test/library-tests/semmle/go/frameworks/Macaron/vendor/gopkg.in/macaron.v1/stub.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,580 @@
|
|||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for gopkg.in/macaron.v1, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: gopkg.in/macaron.v1 (exports: Context; functions: )
|
||||
|
||||
// Package macaron is a stub of gopkg.in/macaron.v1, generated by depstubber.
|
||||
package macaron
|
||||
|
||||
import (
|
||||
context "context"
|
||||
io "io"
|
||||
multipart "mime/multipart"
|
||||
http "net/http"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
type BeforeFunc func(ResponseWriter)
|
||||
|
||||
type ComboRouter struct{}
|
||||
|
||||
func (_ *ComboRouter) Delete(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *ComboRouter) Get(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *ComboRouter) Head(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *ComboRouter) Name(_ string) {}
|
||||
|
||||
func (_ *ComboRouter) Options(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *ComboRouter) Patch(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *ComboRouter) Post(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *ComboRouter) Put(_ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
Injector interface{}
|
||||
Router *Router
|
||||
Req Request
|
||||
Resp ResponseWriter
|
||||
Render Render
|
||||
Locale Locale
|
||||
Data map[string]interface{}
|
||||
}
|
||||
|
||||
func (_ Context) Any(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Apply(_ interface{}) interface {
|
||||
Error() string
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Combo(_ string, _ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Delete(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Error(_ int, _ ...string) {}
|
||||
|
||||
func (_ Context) Get(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) GetVal(_ reflect.Type) reflect.Value {
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
func (_ Context) Group(_ string, _ func(), _ ...Handler) {}
|
||||
|
||||
func (_ Context) HTMLBytes(_ string, _ interface{}, _ ...HTMLOptions) ([]uint8, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ Context) HTMLSetBytes(_ string, _ string, _ interface{}, _ ...HTMLOptions) ([]uint8, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ Context) HTMLSetString(_ string, _ string, _ interface{}, _ ...HTMLOptions) (string, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (_ Context) HTMLString(_ string, _ interface{}, _ ...HTMLOptions) (string, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (_ Context) Handle(_ string, _ string, _ []Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) HasTemplateSet(_ string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Context) Head(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Header() http.Header {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) InternalServerError(_ ...Handler) {}
|
||||
|
||||
func (_ Context) Invoke(_ interface{}) ([]reflect.Value, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ Context) JSON(_ int, _ interface{}) {}
|
||||
|
||||
func (_ Context) JSONString(_ interface{}) (string, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (_ Context) Language() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Context) Map(_ interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) MapTo(_ interface{}, _ interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) NotFound(_ ...Handler) {}
|
||||
|
||||
func (_ Context) Options(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Patch(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) PlainText(_ int, _ []uint8) {}
|
||||
|
||||
func (_ Context) Post(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) Put(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) RawData(_ int, _ []uint8) {}
|
||||
|
||||
func (_ Context) Route(_ string, _ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {}
|
||||
|
||||
func (_ Context) Set(_ reflect.Type, _ reflect.Value) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Context) SetAutoHead(_ bool) {}
|
||||
|
||||
func (_ Context) SetHandlerWrapper(_ func(Handler) Handler) {}
|
||||
|
||||
func (_ Context) SetParent(_ interface{}) {}
|
||||
|
||||
func (_ Context) SetResponseWriter(_ http.ResponseWriter) {}
|
||||
|
||||
func (_ Context) SetTemplatePath(_ string, _ string) {}
|
||||
|
||||
func (_ Context) Status(_ int) {}
|
||||
|
||||
func (_ Context) Tr(_ string, _ ...interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Context) URLFor(_ string, _ ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Context) Write(_ []uint8) (int, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (_ Context) WriteHeader(_ int) {}
|
||||
|
||||
func (_ Context) XML(_ int, _ interface{}) {}
|
||||
|
||||
func (_ *Context) ChangeStaticPath(_ string, _ string) {}
|
||||
|
||||
func (_ *Context) GetCookie(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) GetCookieFloat64(_ string) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) GetCookieInt(_ string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) GetCookieInt64(_ string) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) GetFile(_ string) (multipart.File, *multipart.FileHeader, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (_ *Context) GetSecureCookie(_ string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (_ *Context) GetSuperSecureCookie(_ string, _ string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (_ *Context) HTML(_ int, _ string, _ ...interface{}) {}
|
||||
|
||||
func (_ *Context) HTMLSet(_ int, _ string, _ string, _ ...interface{}) {}
|
||||
|
||||
func (_ *Context) Next() {}
|
||||
|
||||
func (_ *Context) Params(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) ParamsEscape(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) ParamsFloat64(_ string) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) ParamsInt(_ string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) ParamsInt64(_ string) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) Query(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) QueryBool(_ string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ *Context) QueryEscape(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) QueryFloat64(_ string) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) QueryInt(_ string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) QueryInt64(_ string) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ *Context) QueryStrings(_ string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Context) QueryTrim(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) Redirect(_ string, _ ...int) {}
|
||||
|
||||
func (_ *Context) RemoteAddr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Context) ReplaceAllParams(_ Params) {}
|
||||
|
||||
func (_ *Context) SaveToFile(_ string, _ string) interface {
|
||||
Error() string
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Context) ServeContent(_ string, _ io.ReadSeeker, _ ...interface{}) {}
|
||||
|
||||
func (_ *Context) ServeFile(_ string, _ ...string) {}
|
||||
|
||||
func (_ *Context) ServeFileContent(_ string, _ ...string) {}
|
||||
|
||||
func (_ *Context) SetCookie(_ string, _ string, _ ...interface{}) {}
|
||||
|
||||
func (_ *Context) SetParams(_ string, _ string) {}
|
||||
|
||||
func (_ *Context) SetSecureCookie(_ string, _ string, _ ...interface{}) {}
|
||||
|
||||
func (_ *Context) SetSuperSecureCookie(_ string, _ string, _ string, _ ...interface{}) {}
|
||||
|
||||
func (_ *Context) Written() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type HTMLOptions struct {
|
||||
Layout string
|
||||
}
|
||||
|
||||
type Handler interface{}
|
||||
|
||||
type Locale interface {
|
||||
Language() string
|
||||
Tr(_ string, _ ...interface{}) string
|
||||
}
|
||||
|
||||
type Params map[string]string
|
||||
|
||||
type Render interface {
|
||||
Error(_ int, _ ...string)
|
||||
HTML(_ int, _ string, _ interface{}, _ ...HTMLOptions)
|
||||
HTMLBytes(_ string, _ interface{}, _ ...HTMLOptions) ([]uint8, interface {
|
||||
Error() string
|
||||
})
|
||||
HTMLSet(_ int, _ string, _ string, _ interface{}, _ ...HTMLOptions)
|
||||
HTMLSetBytes(_ string, _ string, _ interface{}, _ ...HTMLOptions) ([]uint8, interface {
|
||||
Error() string
|
||||
})
|
||||
HTMLSetString(_ string, _ string, _ interface{}, _ ...HTMLOptions) (string, interface {
|
||||
Error() string
|
||||
})
|
||||
HTMLString(_ string, _ interface{}, _ ...HTMLOptions) (string, interface {
|
||||
Error() string
|
||||
})
|
||||
HasTemplateSet(_ string) bool
|
||||
Header() http.Header
|
||||
JSON(_ int, _ interface{})
|
||||
JSONString(_ interface{}) (string, interface {
|
||||
Error() string
|
||||
})
|
||||
PlainText(_ int, _ []uint8)
|
||||
RawData(_ int, _ []uint8)
|
||||
SetResponseWriter(_ http.ResponseWriter)
|
||||
SetTemplatePath(_ string, _ string)
|
||||
Status(_ int)
|
||||
Write(_ []uint8) (int, interface {
|
||||
Error() string
|
||||
})
|
||||
WriteHeader(_ int)
|
||||
XML(_ int, _ interface{})
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
Request *http.Request
|
||||
}
|
||||
|
||||
func (_ Request) AddCookie(_ *http.Cookie) {}
|
||||
|
||||
func (_ Request) BasicAuth() (string, string, bool) {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
func (_ Request) Clone(_ context.Context) *http.Request {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) Context() context.Context {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) Cookie(_ string) (*http.Cookie, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ Request) Cookies() []*http.Cookie {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) FormFile(_ string) (multipart.File, *multipart.FileHeader, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (_ Request) FormValue(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Request) MultipartReader() (*multipart.Reader, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ Request) ParseForm() interface {
|
||||
Error() string
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) ParseMultipartForm(_ int64) interface {
|
||||
Error() string
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) PostFormValue(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Request) ProtoAtLeast(_ int, _ int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Request) Referer() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Request) SetBasicAuth(_ string, _ string) {}
|
||||
|
||||
func (_ Request) UserAgent() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Request) WithContext(_ context.Context) *http.Request {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) Write(_ io.Writer) interface {
|
||||
Error() string
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Request) WriteProxy(_ io.Writer) interface {
|
||||
Error() string
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Request) Body() *RequestBody {
|
||||
return nil
|
||||
}
|
||||
|
||||
type RequestBody struct{}
|
||||
|
||||
func (_ *RequestBody) Bytes() ([]uint8, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *RequestBody) ReadCloser() io.ReadCloser {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *RequestBody) String() (string, interface {
|
||||
Error() string
|
||||
}) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
type ResponseWriter interface {
|
||||
Before(_ BeforeFunc)
|
||||
Flush()
|
||||
Header() http.Header
|
||||
Size() int
|
||||
Status() int
|
||||
Write(_ []uint8) (int, interface {
|
||||
Error() string
|
||||
})
|
||||
WriteHeader(_ int)
|
||||
Written() bool
|
||||
}
|
||||
|
||||
type Route struct{}
|
||||
|
||||
func (_ *Route) Name(_ string) {}
|
||||
|
||||
type Router struct{}
|
||||
|
||||
func (_ *Router) Any(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Combo(_ string, _ ...Handler) *ComboRouter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Delete(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Get(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Group(_ string, _ func(), _ ...Handler) {}
|
||||
|
||||
func (_ *Router) Handle(_ string, _ string, _ []Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Head(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) InternalServerError(_ ...Handler) {}
|
||||
|
||||
func (_ *Router) NotFound(_ ...Handler) {}
|
||||
|
||||
func (_ *Router) Options(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Patch(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Post(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Put(_ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) Route(_ string, _ string, _ ...Handler) *Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Router) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {}
|
||||
|
||||
func (_ *Router) SetAutoHead(_ bool) {}
|
||||
|
||||
func (_ *Router) SetHandlerWrapper(_ func(Handler) Handler) {}
|
||||
|
||||
func (_ *Router) URLFor(_ string, _ ...string) string {
|
||||
return ""
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# gopkg.in/macaron.v1 v1.3.5
|
||||
## explicit
|
||||
gopkg.in/macaron.v1
|
|
@ -1,5 +1,45 @@
|
|||
| BadRedirectCheck.go:4:23:4:37 | ...==... | This expression checks '$@' for a leading slash but checks do not exist for both '/' and '\\' in the second position. | BadRedirectCheck.go:3:18:3:22 | (def@3:18) | redir |
|
||||
| cves.go:11:26:11:38 | ...==... | This expression checks '$@' for a leading slash but checks do not exist for both '/' and '\\' in the second position. | cves.go:10:22:10:24 | (def@10:22) | url |
|
||||
| cves.go:22:6:22:37 | call to HasPrefix | This expression checks '$@' for a leading slash but checks do not exist for both '/' and '\\' in the second position. | cves.go:21:2:21:9 | (def@21:2) | redirect |
|
||||
| cves.go:29:6:29:37 | call to HasPrefix | This expression checks '$@' for a leading slash but checks do not exist for both '/' and '\\' in the second position. | cves.go:28:2:28:9 | (def@28:2) | redirect |
|
||||
| main.go:8:7:8:38 | call to HasPrefix | This expression checks '$@' for a leading slash but checks do not exist for both '/' and '\\' in the second position. | main.go:5:19:5:26 | (def@5:19) | redirect |
|
||||
edges
|
||||
| BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir : string | BadRedirectCheck.go:5:10:5:14 | redir : string |
|
||||
| BadRedirectCheck.go:5:10:5:14 | redir : string | main.go:11:25:11:45 | call to sanitizeUrl |
|
||||
| cves.go:14:23:14:25 | argument corresponding to url : string | cves.go:16:26:16:28 | url |
|
||||
| cves.go:33:14:33:34 | call to Get : string | cves.go:37:25:37:32 | redirect |
|
||||
| cves.go:41:14:41:34 | call to Get : string | cves.go:45:25:45:32 | redirect |
|
||||
| main.go:10:18:10:25 | argument corresponding to redirect : string | main.go:11:37:11:44 | redirect : string |
|
||||
| main.go:11:37:11:44 | redirect : string | main.go:11:25:11:45 | call to sanitizeUrl |
|
||||
| main.go:32:24:32:26 | argument corresponding to url : string | main.go:34:26:34:28 | url |
|
||||
| main.go:68:17:68:24 | argument corresponding to redirect : string | main.go:73:9:73:28 | call to Clean : string |
|
||||
| main.go:73:9:73:28 | call to Clean : string | main.go:77:25:77:39 | call to getTarget1 |
|
||||
| main.go:76:19:76:21 | argument corresponding to url : string | main.go:77:36:77:38 | url : string |
|
||||
| main.go:77:36:77:38 | url : string | main.go:77:25:77:39 | call to getTarget1 |
|
||||
| main.go:87:9:87:14 | selection of Path : string | main.go:91:25:91:39 | call to getTarget2 |
|
||||
nodes
|
||||
| BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir : string | semmle.label | argument corresponding to redir : string |
|
||||
| BadRedirectCheck.go:5:10:5:14 | redir : string | semmle.label | redir : string |
|
||||
| cves.go:14:23:14:25 | argument corresponding to url : string | semmle.label | argument corresponding to url : string |
|
||||
| cves.go:16:26:16:28 | url | semmle.label | url |
|
||||
| cves.go:33:14:33:34 | call to Get : string | semmle.label | call to Get : string |
|
||||
| cves.go:37:25:37:32 | redirect | semmle.label | redirect |
|
||||
| cves.go:41:14:41:34 | call to Get : string | semmle.label | call to Get : string |
|
||||
| cves.go:45:25:45:32 | redirect | semmle.label | redirect |
|
||||
| main.go:10:18:10:25 | argument corresponding to redirect : string | semmle.label | argument corresponding to redirect : string |
|
||||
| main.go:11:25:11:45 | call to sanitizeUrl | semmle.label | call to sanitizeUrl |
|
||||
| main.go:11:37:11:44 | redirect : string | semmle.label | redirect : string |
|
||||
| main.go:32:24:32:26 | argument corresponding to url : string | semmle.label | argument corresponding to url : string |
|
||||
| main.go:34:26:34:28 | url | semmle.label | url |
|
||||
| main.go:68:17:68:24 | argument corresponding to redirect : string | semmle.label | argument corresponding to redirect : string |
|
||||
| main.go:73:9:73:28 | call to Clean : string | semmle.label | call to Clean : string |
|
||||
| main.go:76:19:76:21 | argument corresponding to url : string | semmle.label | argument corresponding to url : string |
|
||||
| main.go:77:25:77:39 | call to getTarget1 | semmle.label | call to getTarget1 |
|
||||
| main.go:77:36:77:38 | url : string | semmle.label | url : string |
|
||||
| main.go:87:9:87:14 | selection of Path : string | semmle.label | selection of Path : string |
|
||||
| main.go:91:25:91:39 | call to getTarget2 | semmle.label | call to getTarget2 |
|
||||
#select
|
||||
| BadRedirectCheck.go:4:23:4:37 | ...==... | BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir : string | main.go:11:25:11:45 | call to sanitizeUrl | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | BadRedirectCheck.go:3:18:3:22 | argument corresponding to redir | this value | main.go:11:25:11:45 | call to sanitizeUrl | redirect |
|
||||
| BadRedirectCheck.go:4:23:4:37 | ...==... | main.go:10:18:10:25 | argument corresponding to redirect : string | main.go:11:25:11:45 | call to sanitizeUrl | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:10:18:10:25 | argument corresponding to redirect | this value | main.go:11:25:11:45 | call to sanitizeUrl | redirect |
|
||||
| cves.go:11:26:11:38 | ...==... | cves.go:14:23:14:25 | argument corresponding to url : string | cves.go:16:26:16:28 | url | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:14:23:14:25 | argument corresponding to url | this value | cves.go:16:26:16:28 | url | redirect |
|
||||
| cves.go:34:6:34:37 | call to HasPrefix | cves.go:33:14:33:34 | call to Get : string | cves.go:37:25:37:32 | redirect | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:33:14:33:34 | call to Get | this value | cves.go:37:25:37:32 | redirect | redirect |
|
||||
| cves.go:42:6:42:37 | call to HasPrefix | cves.go:41:14:41:34 | call to Get : string | cves.go:45:25:45:32 | redirect | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | cves.go:41:14:41:34 | call to Get | this value | cves.go:45:25:45:32 | redirect | redirect |
|
||||
| main.go:25:7:25:38 | call to HasPrefix | main.go:32:24:32:26 | argument corresponding to url : string | main.go:34:26:34:28 | url | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:32:24:32:26 | argument corresponding to url | this value | main.go:34:26:34:28 | url | redirect |
|
||||
| main.go:69:5:69:22 | ...!=... | main.go:68:17:68:24 | argument corresponding to redirect : string | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:68:17:68:24 | argument corresponding to redirect | this value | main.go:77:25:77:39 | call to getTarget1 | redirect |
|
||||
| main.go:69:5:69:22 | ...!=... | main.go:76:19:76:21 | argument corresponding to url : string | main.go:77:25:77:39 | call to getTarget1 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:76:19:76:21 | argument corresponding to url | this value | main.go:77:25:77:39 | call to getTarget1 | redirect |
|
||||
| main.go:83:5:83:20 | ...!=... | main.go:87:9:87:14 | selection of Path : string | main.go:91:25:91:39 | call to getTarget2 | This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position. | main.go:87:9:87:14 | selection of Path | this value | main.go:91:25:91:39 | call to getTarget2 | redirect |
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package main
|
||||
|
||||
func sanitizeUrl1(redir string) string {
|
||||
func sanitizeUrlGood(redir string) string {
|
||||
if len(redir) > 1 && redir[0] == '/' && redir[1] != '/' && redir[1] != '\\' {
|
||||
return redir
|
||||
}
|
||||
|
|
|
@ -11,10 +11,22 @@ func isValidRedirect(url string) bool {
|
|||
return len(url) >= 2 && url[0] == '/' && url[1] != '/' // NOT OK
|
||||
}
|
||||
|
||||
func isValidRedirect1(url string) bool {
|
||||
func alsoABadRedirect(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
if isValidRedirect(url) {
|
||||
http.Redirect(rw, req, url, 302)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidRedirectGood(url string) bool {
|
||||
return len(url) >= 2 && url[0] == '/' && url[1] != '/' && url[1] != '\\' // OK
|
||||
}
|
||||
|
||||
func alsoAGoodRedirect(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
if isValidRedirectGood(url) {
|
||||
http.Redirect(rw, req, url, 302)
|
||||
}
|
||||
}
|
||||
|
||||
// CVE-2017-1000070 (both vulnerable!)
|
||||
// Code from github.com/bitly/oauth2_proxy
|
||||
func OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
||||
|
@ -22,6 +34,7 @@ func OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
|||
if !strings.HasPrefix(redirect, "/") { // NOT OK
|
||||
redirect = "/"
|
||||
}
|
||||
http.Redirect(rw, req, redirect, 302)
|
||||
}
|
||||
|
||||
func OAuthCallback1(rw http.ResponseWriter, req *http.Request) {
|
||||
|
@ -29,4 +42,5 @@ func OAuthCallback1(rw http.ResponseWriter, req *http.Request) {
|
|||
if !strings.HasPrefix(redirect, "/") || strings.HasPrefix(redirect, "//") { // NOT OK
|
||||
redirect = "/"
|
||||
}
|
||||
http.Redirect(rw, req, redirect, 302)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,23 @@
|
|||
package main
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func badRedirect(redirect string, rw http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(rw, req, sanitizeUrl(redirect), 302)
|
||||
}
|
||||
|
||||
func goodRedirect(redirect string, rw http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(rw, req, sanitizeUrlGood(redirect), 302)
|
||||
}
|
||||
|
||||
func goodRedirect2(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(rw, req, path.Join("/", sanitizeUrl(url)), 302)
|
||||
}
|
||||
|
||||
func isValidRedir(redirect string) bool {
|
||||
switch {
|
||||
|
@ -12,6 +29,12 @@ func isValidRedir(redirect string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func alsoABadRedirect1(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
if isValidRedir(url) {
|
||||
http.Redirect(rw, req, url, 302)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidRedir1(redirect string) bool {
|
||||
switch {
|
||||
// OK
|
||||
|
@ -21,3 +44,49 @@ func isValidRedir1(redirect string) bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func goodRedirect3(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
if isValidRedirectGood(url) {
|
||||
http.Redirect(rw, req, url, 302)
|
||||
}
|
||||
}
|
||||
|
||||
func getTarget(redirect string) string {
|
||||
u, _ := url.Parse(redirect)
|
||||
|
||||
if u.Path[0] != "/" {
|
||||
return "/"
|
||||
}
|
||||
|
||||
return path.Clean(u.Path)
|
||||
}
|
||||
|
||||
func goodRedirect4(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(rw, req, getTarget(url), 302)
|
||||
}
|
||||
|
||||
func getTarget1(redirect string) string {
|
||||
if redirect[0] != "/" {
|
||||
return "/"
|
||||
}
|
||||
|
||||
return path.Clean(redirect)
|
||||
}
|
||||
|
||||
func badRedirect2(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(rw, req, getTarget1(url), 302)
|
||||
}
|
||||
|
||||
func getTarget2(redirect string) string {
|
||||
u, _ := url.Parse(redirect)
|
||||
|
||||
if u.Path[0] != "/" {
|
||||
return "/"
|
||||
}
|
||||
|
||||
return u.Path
|
||||
}
|
||||
|
||||
func badRedirect2(url string, rw http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(rw, req, getTarget2(url), 302)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче