-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(java): add insecure allow origin rule
- Loading branch information
Showing
4 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
imports: | ||
- java_shared_lang_instance | ||
- java_shared_lang_servlet_request | ||
- java_shared_lang_user_input | ||
patterns: | ||
- pattern: | | ||
$<RES>.$<METHOD>($<HEADER>, $<USER_INPUT>); | ||
filters: | ||
- variable: RES | ||
detection: java_shared_lang_instance | ||
scope: cursor | ||
filters: | ||
- variable: JAVA_SHARED_LANG_INSTANCE_TYPE | ||
regex: \A(javax\.servlet\.http\.)?HttpServletResponse\z | ||
- variable: METHOD | ||
values: | ||
- setHeader | ||
- addHeader | ||
- variable: HEADER | ||
string_regex: \A(?i)(Access-Control-Allow-Origin)\z | ||
- variable: USER_INPUT | ||
detection: java_lang_insecure_allow_origin_user_input | ||
auxiliary: | ||
- id: java_lang_insecure_allow_origin_user_input | ||
patterns: | ||
- pattern: $<USER_INPUT>; | ||
filters: | ||
- variable: USER_INPUT | ||
detection: java_shared_lang_user_input | ||
scope: cursor | ||
- pattern: $<USER_INPUT_REQUEST>.$<REQUEST_GET_METHOD>().getAttribute(); | ||
filters: | ||
- variable: USER_INPUT_REQUEST | ||
detection: java_shared_lang_servlet_request | ||
scope: cursor | ||
- variable: REQUEST_GET_METHOD | ||
values: | ||
- getSession | ||
- getServletContext | ||
languages: | ||
- java | ||
metadata: | ||
description: Unsanitized user input in Access-Control-Allow-Origin | ||
remediation_message: | | ||
## Description | ||
Do not use unverified user-defined input to define Access-Control-Allow-Origin. | ||
This can lead to unintended user access to sensitive data. | ||
## Remediations | ||
❌ Avoid defining origins with user input wherever possible. | ||
✅ If unavoidable, be sure to verify the input or to use a safe-list. | ||
## Resources | ||
- [OWASP Origin & Access-Control-Allow-Origin](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/07-Testing_Cross_Origin_Resource_Sharing) | ||
cwe_id: | ||
- 942 | ||
id: java_lang_insecure_allow_origin | ||
documentation_url: https://docs.bearer.com/reference/rules/java_lang_insecure_allow_origin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
const { | ||
createNewInvoker, | ||
getEnvironment, | ||
} = require("../../../helper.js") | ||
const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) | ||
|
||
describe(ruleId, () => { | ||
const invoke = createNewInvoker(ruleId, ruleFile, testBase) | ||
|
||
test("insecure_allow_origin", () => { | ||
const testCase = "main.java" | ||
|
||
const results = invoke(testCase) | ||
|
||
expect(results.Missing).toEqual([]) | ||
expect(results.Extra).toEqual([]) | ||
}) | ||
}) |
120 changes: 120 additions & 0 deletions
120
tests/java/lang/insecure_allow_origin/testdata/main.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package com.test.servlet.cors; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServlet; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
import java.io.IOException; | ||
import java.util.Enumeration; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class Foo extends HttpServlet { | ||
@Override | ||
protected void bad(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { | ||
String paramValue = request.getParameter("bad"); | ||
String header = request.getHeader("bad"); | ||
String queryString = request.getQueryString(); | ||
|
||
String[] parameterValues = request.getParameterValues("URL"); | ||
Enumeration<String> parameterNames = request.getParameterNames(); | ||
Map<String, String[]> parameterMap = request.getParameterMap(); | ||
|
||
String indexedParameterValue = parameterValues[0]; | ||
String parameterNamesElem = parameterNames.nextElement(); | ||
String indexedValueFromParameterMap = parameterMap.get("URL")[0]; | ||
|
||
if (paramValue != null) { | ||
// bearer:expected java_lang_insecure_allow_origin | ||
response.setHeader("Access-Control-Allow-Origin", paramValue); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("Access-Control-Allow-Origin", paramValue); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", paramValue); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", header); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", indexedParameterValue); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", parameterNamesElem); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", indexedValueFromParameterMap); | ||
|
||
String[] keyValuePairs = queryString.split("="); | ||
String lastPair = keyValuePairs[keyValuePairs.length - 1]; | ||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", lastPair); | ||
|
||
String headerName = "ACCESS-CONTROL-ALLOW-ORIGIN"; | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader(headerName, paramValue); | ||
|
||
return; | ||
} | ||
} | ||
|
||
public void badSessionAttr(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||
request.getSession().setAttribute("someAttrName", request.getParameter("bad")); | ||
String sessionAttr = (String) request.getSession().getAttribute("attributeName"); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", sessionAttr); | ||
} | ||
|
||
public void badRequestAttr(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||
request.setAttribute("someAttrName",request.getParameter("bad")); | ||
String requestAttr = (String) request.getAttribute("someAttrName"); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", requestAttr); | ||
} | ||
|
||
public void badServletContext(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||
request.getServletContext().setAttribute("someAttrName",request.getParameter("bad")); | ||
String contextAttr = (String) request.getServletContext().getAttribute("someAttrName"); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("access-control-allow-origin", contextAttr); | ||
} | ||
|
||
public void badModifiedPath(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||
String pathInfo = request.getPathInfo(); | ||
String modifiedPath = pathInfo.replaceFirst("/",""); | ||
|
||
// bearer:expected java_lang_insecure_allow_origin | ||
response.addHeader("Access-Control-Allow-Origin", modifiedPath); | ||
} | ||
|
||
public void ok(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||
String paramValue = request.getParameter("bad"); | ||
if paramValue != null { | ||
// set some other header with user-input | ||
response.setHeader("X-Example-Header", paramValue); | ||
} | ||
|
||
String pathInfo = request.getPathInfo(); | ||
String modifiedPath = pathInfo.replaceFirst("/",""); | ||
// set some other header with user-input | ||
response.setHeader("X-Example-Header", modifiedPath); | ||
|
||
response.setHeader("Access-Control-Allow-Origin", "https://example.com"); | ||
response.addHeader("Access-Control-Allow-Origin", "https://example.com"); | ||
response.addHeader("Access-Control-Allow-Origin", getFromList("key")); | ||
// bad for other reasons! | ||
response.addHeader("Access-Control-Allow-Origin", "*"); | ||
} | ||
|
||
public String getFromList(String key){ | ||
HashMap<String, String> corsList = new HashMap<>(); | ||
corsList.put("key", "https://example.com"); | ||
|
||
return corsList.get(key); | ||
} | ||
} |