diff --git a/src/sarif_converter.ts b/src/sarif_converter.ts index f4f585e4..34695412 100644 --- a/src/sarif_converter.ts +++ b/src/sarif_converter.ts @@ -47,7 +47,9 @@ function getSuggestions(analysisResults: IAnalysisResult): ISarifSuggestions { if (!Object.keys(suggestions).includes(issueId)) { suggestions[issueId] = []; } - suggestions[issueId].push({ ...issues[0], file: file.substring(1) }); + issues.forEach(issue => { + suggestions[issueId].push({ ...issue, file: file.substring(1) }); + }); } } return suggestions; diff --git a/tests/__snapshots__/sarif_converter.spec.ts.snap b/tests/__snapshots__/sarif_converter.spec.ts.snap new file mode 100644 index 00000000..e212cd7a --- /dev/null +++ b/tests/__snapshots__/sarif_converter.spec.ts.snap @@ -0,0 +1,2125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Sarif Convertor should test no changes have occured in the sarif 1`] = ` +Object { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": Array [ + Object { + "properties": Object { + "coverage": Array [ + Object { + "files": 56, + "isSupported": false, + "lang": "Shell", + }, + Object { + "files": 167, + "isSupported": false, + "lang": "YAML", + }, + Object { + "files": 189, + "isSupported": false, + "lang": "Unknown", + }, + Object { + "files": 47, + "isSupported": false, + "lang": "Markdown", + }, + Object { + "files": 328, + "isSupported": false, + "lang": "XML", + }, + Object { + "files": 22, + "isSupported": false, + "lang": "Text", + }, + Object { + "files": 2557, + "isSupported": true, + "lang": "Java", + }, + Object { + "files": 4, + "isSupported": false, + "lang": "SVG", + }, + Object { + "files": 41, + "isSupported": true, + "lang": "JavaScript", + }, + Object { + "files": 13, + "isSupported": false, + "lang": "CSS", + }, + Object { + "files": 14, + "isSupported": true, + "lang": "HTML", + }, + Object { + "files": 21, + "isSupported": false, + "lang": "Java Properties", + }, + Object { + "files": 89, + "isSupported": false, + "lang": "SQLPL", + }, + Object { + "files": 88, + "isSupported": true, + "lang": "TypeScript", + }, + Object { + "files": 72, + "isSupported": false, + "lang": "JSON", + }, + Object { + "files": 8, + "isSupported": false, + "lang": "Smarty", + }, + Object { + "files": 1, + "isSupported": false, + "lang": "TOML", + }, + Object { + "files": 28, + "isSupported": false, + "lang": "FreeMarker", + }, + Object { + "files": 6, + "isSupported": false, + "lang": "HTML+ERB", + }, + Object { + "files": 3, + "isSupported": false, + "lang": "PHP (beta)", + }, + Object { + "files": 3, + "isSupported": false, + "lang": "C# (beta)", + }, + Object { + "files": 57, + "isSupported": false, + "lang": "Java Server Pages", + }, + Object { + "files": 4, + "isSupported": false, + "lang": "C++ (beta)", + }, + Object { + "files": 1, + "isSupported": false, + "lang": "C (beta)", + }, + Object { + "files": 4, + "isSupported": false, + "lang": "Python", + }, + Object { + "files": 4, + "isSupported": false, + "lang": "Less", + }, + Object { + "files": 4, + "isSupported": false, + "lang": "Go", + }, + ], + }, + "results": Array [ + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 44, + "endLine": 45, + "startColumn": 9, + "startLine": 45, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "ae785dddd67d66083bf565a2ab826535bac183b3c477d249649c6596f2405dd6", + "1": "12342", + }, + "level": "note", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 44, + "endLine": 45, + "startColumn": 9, + "startLine": 45, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[promise](0)", + ], + "markdown": "No catch method for promise. This may result in an unhandled promise rejection.", + "text": "No catch method for {0}. This may result in an unhandled promise rejection.", + }, + "ruleId": "javascript/PromiseNotCaughtGeneral", + "ruleIndex": 0, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 44, + "endLine": 97, + "startColumn": 9, + "startLine": 97, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "1d9d2bce6036443e56e61ffb689caca291b33055d37810ba48423aae6eb29d16", + }, + "level": "note", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 44, + "endLine": 97, + "startColumn": 9, + "startLine": 97, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[promise](0)", + ], + "markdown": "No catch method for promise. This may result in an unhandled promise rejection.", + "text": "No catch method for {0}. This may result in an unhandled promise rejection.", + }, + "ruleId": "javascript/PromiseNotCaughtGeneral", + "ruleIndex": 0, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/index.html", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 41, + "endLine": 108, + "startColumn": 9, + "startLine": 108, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "c8ede54bd6611ca074c42baf78809b9fe198c762ba8a1a78571befdf191869e5", + }, + "level": "note", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/index.html", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 41, + "endLine": 108, + "startColumn": 9, + "startLine": 108, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[promise](0)", + ], + "markdown": "No catch method for promise. This may result in an unhandled promise rejection.", + "text": "No catch method for {0}. This may result in an unhandled promise rejection.", + }, + "ruleId": "javascript/PromiseNotCaughtGeneral", + "ruleIndex": 0, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 30, + "endLine": 1052, + "startColumn": 17, + "startLine": 1052, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "8105a5e15b9d725e663009985913a6931ba94ddd56f4854d24ba3565067501b4", + }, + "level": "note", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 30, + "endLine": 1052, + "startColumn": 17, + "startLine": 1052, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[promise](0)", + ], + "markdown": "No catch method for promise. This may result in an unhandled promise rejection.", + "text": "No catch method for {0}. This may result in an unhandled promise rejection.", + }, + "ruleId": "javascript/PromiseNotCaughtGeneral", + "ruleIndex": 0, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 53, + "endLine": 84, + "startColumn": 13, + "startLine": 84, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "8a870ceae63c99fb925bcdcbaca7ce5c8ccf29024898cd1694d930b5d687842e", + }, + "level": "note", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 53, + "endLine": 84, + "startColumn": 13, + "startLine": 84, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[promise](0)", + ], + "markdown": "No catch method for promise. This may result in an unhandled promise rejection.", + "text": "No catch method for {0}. This may result in an unhandled promise rejection.", + }, + "ruleId": "javascript/PromiseNotCaughtGeneral", + "ruleIndex": 0, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 175, + "startColumn": 14, + "startLine": 175, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 175, + "startColumn": 14, + "startLine": 175, + }, + }, + }, + }, + Object { + "location": Object { + "id": 2, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 31, + "endLine": 23, + "startColumn": 25, + "startLine": 23, + }, + }, + }, + }, + Object { + "location": Object { + "id": 3, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 21, + "endLine": 23, + "startColumn": 5, + "startLine": 23, + }, + }, + }, + }, + Object { + "location": Object { + "id": 4, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 21, + "endLine": 23, + "startColumn": 13, + "startLine": 23, + }, + }, + }, + }, + Object { + "location": Object { + "id": 5, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 11, + "endLine": 23, + "startColumn": 5, + "startLine": 23, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "c92fd0d8fbb0722ac17a8dfd6b9fd5c0770a64a3f965ed128ecc6ae45c20813b", + }, + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/oauthLoader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 11, + "endLine": 23, + "startColumn": 5, + "startLine": 23, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[an exception](0)", + "[flows](1),(2),(3),(4)", + "[0](5)", + ], + "markdown": "Unsanitized input from an exception flows into 0, where it is used to dynamically construct the HTML page on client side. This may result in a DOM Based Cross-Site Scripting attack (DOMXSS).", + "text": "Unsanitized input from {0} {1} into {2}, where it is used to dynamically construct the HTML page on client side. This may result in a DOM Based Cross-Site Scripting attack (DOMXSS).", + }, + "ruleId": "javascript/DOMXSS", + "ruleIndex": 1, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 235, + "startColumn": 14, + "startLine": 235, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 235, + "startColumn": 14, + "startLine": 235, + }, + }, + }, + }, + Object { + "location": Object { + "id": 2, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 34, + "endLine": 236, + "startColumn": 23, + "startLine": 236, + }, + }, + }, + }, + Object { + "location": Object { + "id": 3, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 33, + "endLine": 238, + "startColumn": 22, + "startLine": 238, + }, + }, + }, + }, + Object { + "location": Object { + "id": 4, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 17, + "endLine": 35, + "startColumn": 11, + "startLine": 35, + }, + }, + }, + }, + Object { + "location": Object { + "id": 5, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 35, + "endLine": 42, + "startColumn": 29, + "startLine": 42, + }, + }, + }, + }, + Object { + "location": Object { + "id": 6, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 42, + "startColumn": 9, + "startLine": 42, + }, + }, + }, + }, + Object { + "location": Object { + "id": 7, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 42, + "startColumn": 17, + "startLine": 42, + }, + }, + }, + }, + Object { + "location": Object { + "id": 8, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 15, + "endLine": 42, + "startColumn": 9, + "startLine": 42, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "2ea8d6c4f7096751e5e6f725a3deeac983fe5fac17cdd64e5f6aa83d49156d67", + }, + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-root-war/src/main/webapp/_app/loader.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 20, + "endLine": 238, + "startColumn": 9, + "startLine": 238, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[an exception](0)", + "[flows](1),(2),(3),(4),(5),(6),(7)", + "[0](8)", + ], + "markdown": "Unsanitized input from an exception flows into 0, where it is used to dynamically construct the HTML page on client side. This may result in a DOM Based Cross-Site Scripting attack (DOMXSS).", + "text": "Unsanitized input from {0} {1} into {2}, where it is used to dynamically construct the HTML page on client side. This may result in a DOM Based Cross-Site Scripting attack (DOMXSS).", + }, + "ruleId": "javascript/DOMXSS", + "ruleIndex": 1, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/index.html", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 60, + "endLine": 53, + "startColumn": 29, + "startLine": 53, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/index.html", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 21, + "endLine": 51, + "startColumn": 13, + "startLine": 51, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object {}, + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/index.html", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 21, + "endLine": 51, + "startColumn": 13, + "startLine": 51, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[a hardcoded string](0)", + "[initOAuth](1)", + ], + "markdown": "Avoid hardcoding values that are meant to be secret. Found a hardcoded string used in initOAuth.", + "text": "Avoid hardcoding values that are meant to be secret. Found {0} used in {1}.", + }, + "ruleId": "javascript/HardcodedNonCryptoSecret", + "ruleIndex": 2, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/marked.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 35, + "endLine": 215, + "startColumn": 31, + "startLine": 215, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/marked.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 29, + "endLine": 215, + "startColumn": 16, + "startLine": 215, + }, + }, + }, + }, + Object { + "location": Object { + "id": 2, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/marked.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 35, + "endLine": 215, + "startColumn": 31, + "startLine": 215, + }, + }, + }, + }, + Object { + "location": Object { + "id": 3, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/marked.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 35, + "endLine": 215, + "startColumn": 31, + "startLine": 215, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "719d356d9a2efebe9142ca79825c6c0e4b0e6f5013a6e3f3b04630243416ac87", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/marked.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 29, + "endLine": 215, + "startColumn": 16, + "startLine": 215, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[regex](0)", + "[replace](1)", + "[/\\\\r?\\\\n$/](2)", + "[to handle different new lines](3)", + ], + "markdown": "The pattern regex in replace may be improved to /\\\\r?\\\\n$/to handle different new lines.", + "text": "The pattern {0} in {1} may be improved to {2}{3}.", + }, + "ruleId": "javascript/ReplacementRegex", + "ruleIndex": 3, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/swagger-oauth.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 38, + "endLine": 98, + "startColumn": 3, + "startLine": 98, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "78d8a8779142d82cf9be9da7a167e8e06236ab0a67d324143494650a5e4badf2", + "1": "asdf", + "2": "78d8a8779142d82cf9be9da7a167e8e06236ab0a67d324143494650a5e4badf2", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/swagger-oauth.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 38, + "endLine": 98, + "startColumn": 3, + "startLine": 98, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[unbind()](0)", + ], + "markdown": "Use off() instead of unbind().", + "text": "Use off() instead of {0}.", + }, + "ruleId": "javascript/UseInstead", + "ruleIndex": 4, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/swagger-oauth.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 21, + "endLine": 216, + "startColumn": 3, + "startLine": 216, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "ce5c43465aac96db6e4505f48df1defaa81a38bf7876a1f0e7431c54304d9ea1", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-swagger-war/src/main/webapp/lib/swagger-oauth.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 21, + "endLine": 216, + "startColumn": 3, + "startLine": 216, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[unbind()](0)", + ], + "markdown": "Use off() instead of unbind().", + "text": "Use off() instead of {0}.", + }, + "ruleId": "javascript/UseInstead", + "ruleIndex": 4, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 65, + "endLine": 408, + "startColumn": 50, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 65, + "endLine": 408, + "startColumn": 50, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 2, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 48, + "endLine": 408, + "startColumn": 39, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 3, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 66, + "endLine": 408, + "startColumn": 39, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 4, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 35, + "endLine": 408, + "startColumn": 25, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 5, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 35, + "endLine": 408, + "startColumn": 28, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 6, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 26, + "endLine": 408, + "startColumn": 25, + "startLine": 408, + }, + }, + }, + }, + Object { + "location": Object { + "id": 7, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 45, + "endLine": 409, + "startColumn": 44, + "startLine": 409, + }, + }, + }, + }, + Object { + "location": Object { + "id": 8, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 10, + "endLine": 421, + "startColumn": 9, + "startLine": 421, + }, + }, + }, + }, + Object { + "location": Object { + "id": 9, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 10, + "endLine": 438, + "startColumn": 9, + "startLine": 438, + }, + }, + }, + }, + Object { + "location": Object { + "id": 10, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 10, + "endLine": 529, + "startColumn": 9, + "startLine": 529, + }, + }, + }, + }, + Object { + "location": Object { + "id": 11, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 25, + "endLine": 540, + "startColumn": 24, + "startLine": 540, + }, + }, + }, + }, + Object { + "location": Object { + "id": 12, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 54, + "endLine": 347, + "startColumn": 53, + "startLine": 347, + }, + }, + }, + }, + Object { + "location": Object { + "id": 13, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 63, + "endLine": 347, + "startColumn": 53, + "startLine": 347, + }, + }, + }, + }, + Object { + "location": Object { + "id": 14, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 66, + "endLine": 367, + "startColumn": 56, + "startLine": 367, + }, + }, + }, + }, + Object { + "location": Object { + "id": 15, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 66, + "endLine": 367, + "startColumn": 44, + "startLine": 367, + }, + }, + }, + }, + Object { + "location": Object { + "id": 16, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 42, + "endLine": 367, + "startColumn": 26, + "startLine": 367, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "2cc2fb05feccfae008104250873928e0d9f1de01f5878d485963f2966edc163e", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 67, + "endLine": 367, + "startColumn": 26, + "startLine": 367, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[data from a remote resource](0)", + "[flows](1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15)", + "[this object](16)", + ], + "markdown": "Unsanitized input from data from a remote resource flows into a member access and is used to access a property of this object by name. This may allow a malicious user to access methods (e.g. toString) as opposed to regular properties of objects and cause a crash, remote code execution or more serious problems. This is known as a Prototype Pollution vulnerability.", + "text": "Unsanitized input from {0} {1} into a member access and is used to access a property of {2} by name. This may allow a malicious user to access methods (e.g. toString) as opposed to regular properties of objects and cause a crash, remote code execution or more serious problems. This is known as a Prototype Pollution vulnerability.", + }, + "ruleId": "javascript/UserControlledProperty", + "ruleIndex": 5, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 61, + "endLine": 375, + "startColumn": 44, + "startLine": 375, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 32, + "endLine": 375, + "startColumn": 13, + "startLine": 375, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "4aaff40942701a6acc92fafebea49f718bdc060012ca10a5f30e9462da6143b9", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 61, + "endLine": 375, + "startColumn": 44, + "startLine": 375, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[application/json](0)", + "[setRequestHeader](1)", + ], + "markdown": "Content-type application/json set in setRequestHeader does not specify a charset. Add charset=utf-8 or another charset.", + "text": "Content-type {0} set in {1} does not specify a charset. Add charset=utf-8 or another charset.", + }, + "ruleId": "javascript/ContentTypeNoCharset", + "ruleIndex": 6, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 61, + "endLine": 400, + "startColumn": 44, + "startLine": 400, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 32, + "endLine": 400, + "startColumn": 13, + "startLine": 400, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "51a2aefac0251d664f40c9741ab9a6af0ad1cdd7a51423db9de5891777960016", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 61, + "endLine": 400, + "startColumn": 44, + "startLine": 400, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[application/json](0)", + "[setRequestHeader](1)", + ], + "markdown": "Content-type application/json set in setRequestHeader does not specify a charset. Add charset=utf-8 or another charset.", + "text": "Content-type {0} set in {1} does not specify a charset. Add charset=utf-8 or another charset.", + }, + "ruleId": "javascript/ContentTypeNoCharset", + "ruleIndex": 6, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 65, + "endLine": 737, + "startColumn": 48, + "startLine": 737, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 36, + "endLine": 737, + "startColumn": 17, + "startLine": 737, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "da1a56ce99d2778caea9103d4aba2292543efa487853e8c161c4573aec8b62f1", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 65, + "endLine": 737, + "startColumn": 48, + "startLine": 737, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[application/json](0)", + "[setRequestHeader](1)", + ], + "markdown": "Content-type application/json set in setRequestHeader does not specify a charset. Add charset=utf-8 or another charset.", + "text": "Content-type {0} set in {1} does not specify a charset. Add charset=utf-8 or another charset.", + }, + "ruleId": "javascript/ContentTypeNoCharset", + "ruleIndex": 6, + }, + Object { + "codeFlows": Array [ + Object { + "threadFlows": Array [ + Object { + "locations": Array [ + Object { + "location": Object { + "id": 0, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 73, + "endLine": 794, + "startColumn": 56, + "startLine": 794, + }, + }, + }, + }, + Object { + "location": Object { + "id": 1, + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 44, + "endLine": 794, + "startColumn": 25, + "startLine": 794, + }, + }, + }, + }, + ], + }, + ], + }, + ], + "fingerprints": Object { + "0": "81afc8333354c3ccd0a8264aab07846cb5a69b35bbeff7a9b6bcdb9fcf3689d0", + }, + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": "assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/keycloak/OIDCKeycloak.js", + "uriBaseId": "%SRCROOT%", + }, + "region": Object { + "endColumn": 73, + "endLine": 794, + "startColumn": 56, + "startLine": 794, + }, + }, + }, + ], + "message": Object { + "arguments": Array [ + "[application/json](0)", + "[setRequestHeader](1)", + ], + "markdown": "Content-type application/json set in setRequestHeader does not specify a charset. Add charset=utf-8 or another charset.", + "text": "Content-type {0} set in {1} does not specify a charset. Add charset=utf-8 or another charset.", + }, + "ruleId": "javascript/ContentTypeNoCharset", + "ruleIndex": 6, + }, + ], + "tool": Object { + "driver": Object { + "name": "SnykCode", + "rules": Array [ + Object { + "defaultConfiguration": Object { + "level": "note", + }, + "help": Object { + "markdown": "", + "text": "", + }, + "id": "javascript/PromiseNotCaughtGeneral", + "name": "PromiseNotCaughtGeneral", + "properties": Object { + "categories": Array [ + "API", + "Info", + ], + "exampleCommitDescriptions": Array [ + "* fix test error", + "testing with promises should return the promise", + ], + "exampleCommitFixes": Array [], + "precision": "very-high", + "tags": Array [ + "javascript", + "maintenance", + "error", + "tests", + "promise", + ], + }, + "shortDescription": Object { + "text": "PromiseNotCaughtGeneral", + }, + }, + Object { + "defaultConfiguration": Object { + "level": "error", + }, + "help": Object { + "markdown": "## Details + +A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source. + +This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser's Same Origin Policy. + +Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability. + +Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, \`<\` can be coded as \`<\`; and \`>\` can be coded as \`>\`; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses \`<\` and \`>\` as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they've been correctly escaped in the application code and in this way the attempted attack is diverted. + +The most prominent use of XSS is to steal cookies (source: OWASP HttpOnly) and hijack user sessions, but XSS exploits have been used to expose sensitive information, enable access to privileged services and functionality and deliver malware. + +### Types of attacks +There are a few methods by which XSS can be manipulated: + +|Type|Origin|Description| +|--|--|--| +|**Stored**|Server|The malicious code is inserted in the application (usually as a link) by the attacker. The code is activated every time a user clicks the link.| +|**Reflected**|Server|The attacker delivers a malicious link externally from the vulnerable web site application to a user. When clicked, malicious code is sent to the vulnerable web site, which reflects the attack back to the user's browser.| +|**DOM-based**|Client|The attacker forces the user's browser to render a malicious page. The data in the page itself delivers the cross-site scripting data.| +|**Mutated**| |The attacker injects code that appears safe, but is then rewritten and modified by the browser, while parsing the markup. An example is rebalancing unclosed quotation marks or even adding quotation marks to unquoted parameters.| + +### Affected environments +The following environments are susceptible to an XSS attack: + +* Web servers +* Application servers +* Web application environments + +### How to prevent +This section describes the top best practices designed to specifically protect your code: + +* Sanitize data input in an HTTP request before reflecting it back, ensuring all data is validated, filtered or escaped before echoing anything back to the user, such as the values of query parameters during searches. +* Convert special characters such as \`?\`, \`&\`, \`/\`, \`<\`, \`>\` and spaces to their respective HTML or URL encoded equivalents. +* Give users the option to disable client-side scripts. +* Redirect invalid requests. +* Detect simultaneous logins, including those from two separate IP addresses, and invalidate those sessions. +* Use and enforce a Content Security Policy (source: Wikipedia) to disable any features that might be manipulated for an XSS attack. +* Read the documentation for any of the libraries referenced in your code to understand which elements allow for embedded HTML.", + "text": "", + }, + "id": "javascript/DOMXSS", + "name": "DOMXSS", + "properties": Object { + "categories": Array [ + "Security", + ], + "cwe": Array [ + "CWE-79", + ], + "exampleCommitDescriptions": Array [ + "* Ensure that dgrid.css is explicitly loaded in all test pages", + "Added compound test suite and updated QUnit.", + "ExampleWidget for testing LESS compilation and load!", + ], + "exampleCommitFixes": Array [], + "precision": "very-high", + "tags": Array [ + "javascript", + "maintenance", + "usability", + "page", + "QUnit", + "loading", + ], + }, + "shortDescription": Object { + "text": "Cross-site Scripting (XSS)", + }, + }, + Object { + "defaultConfiguration": Object { + "level": "error", + }, + "help": Object { + "markdown": "", + "text": "", + }, + "id": "javascript/HardcodedNonCryptoSecret", + "name": "HardcodedNonCryptoSecret", + "properties": Object { + "categories": Array [ + "Security", + ], + "cwe": Array [ + "CWE-547", + ], + "exampleCommitDescriptions": Array [ + "Make address, passphrase and secret in the tests configurable", + "clean console.log + update test for express session", + "use config for tests", + ], + "exampleCommitFixes": Array [], + "precision": "very-high", + "tags": Array [ + "javascript", + "maintenance", + "secret", + "session", + "config", + ], + }, + "shortDescription": Object { + "text": "Hardcoded Secret", + }, + }, + Object { + "defaultConfiguration": Object { + "level": "warning", + }, + "help": Object { + "markdown": "", + "text": "", + }, + "id": "javascript/ReplacementRegex", + "name": "ReplacementRegex", + "properties": Object { + "categories": Array [ + "Defect", + ], + "exampleCommitDescriptions": Array [ + "Fix match on ending newline bug", + "Better logging for favicons.", + "* Even better auth switching and timeline syntax", + ], + "exampleCommitFixes": Array [], + "precision": "very-high", + "tags": Array [ + "javascript", + "upgrade", + "maintenance", + "bug", + "newline", + "favicon", + "auth", + ], + }, + "shortDescription": Object { + "text": "ReplacementRegex", + }, + }, + Object { + "defaultConfiguration": Object { + "level": "warning", + }, + "help": Object { + "markdown": "", + "text": "", + }, + "id": "javascript/UseInstead", + "name": "UseInstead", + "properties": Object { + "categories": Array [ + "API", + ], + "exampleCommitDescriptions": Array [ + "- Replaced all the $ for jQuery in the tests and suite.", + "new event map and tests", + "testing using on instead of bind", + ], + "exampleCommitFixes": Array [], + "precision": "very-high", + "tags": Array [ + "javascript", + "maintenance", + "bug", + "jQuery", + "event", + "binding", + ], + }, + "shortDescription": Object { + "text": "UseInstead", + }, + }, + Object { + "defaultConfiguration": Object { + "level": "warning", + }, + "help": Object { + "markdown": "", + "text": "", + }, + "id": "javascript/UserControlledProperty", + "name": "UserControlledProperty", + "properties": Object { + "categories": Array [ + "Security", + ], + "exampleCommitDescriptions": Array [], + "exampleCommitFixes": Array [], + "precision": "very-high", + "tags": Array [ + "javascript", + ], + }, + "shortDescription": Object { + "text": "UserControlledProperty", + }, + }, + Object { + "defaultConfiguration": Object { + "level": "warning", + }, + "help": Object { + "markdown": "", + "text": "", + }, + "id": "javascript/ContentTypeNoCharset", + "name": "ContentTypeNoCharset", + "properties": Object { + "categories": Array [ + "Defect", + ], + "exampleCommitDescriptions": Array [ + "Added charset to content-type headers in tests", + ], + "exampleCommitFixes": Array [ + Object { + "commitURL": "https://github.com/FabMo/FabMo-Engine/commit/25fc0c92e6f6f00e5a30fe8cd6f520599c7a4510?diff=split#diff-87379c668bab67fbe451d528e856c4a7L574", + "lines": Array [ + Object { + "line": "if(!(data instanceof FormData)) {", + "lineChange": "none", + "lineNumber": 578, + }, + Object { + "line": " xhr.setRequestHeader('Content-Type', 'application/json');", + "lineChange": "removed", + "lineNumber": 573, + }, + Object { + "line": " xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');", + "lineChange": "added", + "lineNumber": 579, + }, + Object { + "line": " if(typeof data != 'string') {", + "lineChange": "none", + "lineNumber": 580, + }, + Object { + "line": " data = JSON.stringify(data);", + "lineChange": "none", + "lineNumber": 581, + }, + ], + }, + Object { + "commitURL": "https://github.com/Inpassor/centrifuge-ts/commit/b00e64314651b6990ba45c3f000a02dcf25dee0f?diff=split#diff-f658bd2547156630632595517b820ecdL458", + "lines": Array [ + Object { + "line": "}", + "lineChange": "removed", + "lineNumber": 455, + }, + Object { + "line": "xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');", + "lineChange": "removed", + "lineNumber": 456, + }, + Object { + "line": "xhr.setRequestHeader('Content-Type', 'application/json');", + "lineChange": "removed", + "lineNumber": 457, + }, + Object { + "line": "var _headers = new Headers();", + "lineChange": "added", + "lineNumber": 423, + }, + Object { + "line": "_headers.append('X-Requested-With', 'XMLHttpRequest');", + "lineChange": "added", + "lineNumber": 424, + }, + Object { + "line": "_headers.append('Content-Type', 'application/json');", + "lineChange": "added", + "lineNumber": 425, + }, + Object { + "line": "for (var headerName in headers) {", + "lineChange": "none", + "lineNumber": 458, + }, + Object { + "line": " if (headers.hasOwnProperty(headerName)) {", + "lineChange": "none", + "lineNumber": 459, + }, + ], + }, + Object { + "commitURL": "https://github.com/infermedica/js-symptom-checker-example/commit/2763d02a591081da11a6c241feb01bbf1a3a260d?diff=split#diff-424c2d7fee9a65c1537c6183d3d4f1e4L23", + "lines": Array [ + Object { + "line": " req.setRequestHeader('App-Key', this.appKey);", + "lineChange": "removed", + "lineNumber": 20, + }, + Object { + "line": " req.setRequestHeader('Model', this.apiModel);", + "lineChange": "removed", + "lineNumber": 21, + }, + Object { + "line": " req.setRequestHeader('Content-Type', 'application/json');", + "lineChange": "removed", + "lineNumber": 22, + }, + Object { + "line": " req.onload = () => {", + "lineChange": "removed", + "lineNumber": 24, + }, + Object { + "line": "headers.append('app-key', this.appKey);", + "lineChange": "added", + "lineNumber": 17, + }, + Object { + "line": "headers.append('model', this.apiModel);", + "lineChange": "added", + "lineNumber": 18, + }, + Object { + "line": "headers.append('content-type', 'application/json');", + "lineChange": "added", + "lineNumber": 19, + }, + Object { + "line": "return fetch(this.apiUrl + url, {", + "lineChange": "added", + "lineNumber": 21, + }, + ], + }, + ], + "precision": "very-high", + "tags": Array [ + "javascript", + "bug", + "maintenance", + "charset", + "contenttype", + "header", + ], + }, + "shortDescription": Object { + "text": "ContentTypeNoCharset", + }, + }, + ], + "semanticVersion": "1.0.0", + "version": "1.0.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/Assignment5.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/Assignment5.java new file mode 100644 index 00000000..e583d72a --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/Assignment5.java @@ -0,0 +1,70 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.challenges.challenge5; + +import lombok.extern.slf4j.Slf4j; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.challenges.Flag; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.sql.DataSource; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +@RestController +@Slf4j +public class Assignment5 extends AssignmentEndpoint { + + private final DataSource dataSource; + + public Assignment5(DataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/challenge/5") + @ResponseBody + public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception { + if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) { + return failed(this).feedback("required4").build(); + } + if (!"Larry".equals(username_login)) { + return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build(); + } + try (var connection = dataSource.getConnection()) { + PreparedStatement statement = connection.prepareStatement("select password from challenge_users where userid = '" + username_login + "' and password = '" + password_login + "'"); + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build(); + } else { + return failed(this).feedback("challenge.close").build(); + } + } + } +} + diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/DeserializeTest.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/DeserializeTest.java new file mode 100644 index 00000000..765a9e8c --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/DeserializeTest.java @@ -0,0 +1,93 @@ +package org.owasp.webgoat.deserialization; + +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +import org.dummy.insecure.framework.VulnerableTaskHolder; +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import org.owasp.webgoat.assignments.AssignmentEndpointTest; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +@RunWith(MockitoJUnitRunner.class) +public class DeserializeTest extends AssignmentEndpointTest { + + private MockMvc mockMvc; + + private static String OS = System.getProperty("os.name").toLowerCase(); + + @Before + public void setup() { + InsecureDeserializationTask insecureTask = new InsecureDeserializationTask(); + init(insecureTask); + this.mockMvc = standaloneSetup(insecureTask).build(); + } + + @Test + public void success() throws Exception { + if (OS.indexOf("win")>-1) { + mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .header("x-request-intercepted", "true") + .param("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5")))) + .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); + } else { + mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .header("x-request-intercepted", "true") + .param("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")))) + .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); + } + } + + @Test + public void fail() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .header("x-request-intercepted", "true") + .param("token", SerializationHelper.toString(new VulnerableTaskHolder("delete", "rm *")))) + .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); + } + + @Test + public void wrongVersion() throws Exception { + String token = "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAECAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4GIQgMLRSoeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; + mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .header("x-request-intercepted", "true") + .param("token", token)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("insecure-deserialization.invalidversion")))) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } + + @Test + public void expiredTask() throws Exception { + String token = "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4IDC0YfvNIeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; + mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .header("x-request-intercepted", "true") + .param("token", token)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("insecure-deserialization.expired")))) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } + + + + @Test + public void checkOtherObject() throws Exception { + String token = "rO0ABXQAVklmIHlvdSBkZXNlcmlhbGl6ZSBtZSBkb3duLCBJIHNoYWxsIGJlY29tZSBtb3JlIHBvd2VyZnVsIHRoYW4geW91IGNhbiBwb3NzaWJseSBpbWFnaW5l"; + mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .header("x-request-intercepted", "true") + .param("token", token)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("insecure-deserialization.stringobject")))) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } + + + +} \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/HashingAssignment.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/HashingAssignment.java new file mode 100644 index 00000000..b5dc69fd --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/HashingAssignment.java @@ -0,0 +1,111 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.crypto; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Random; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.bind.DatatypeConverter; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@AssignmentHints({"crypto-hashing.hints.1","crypto-hashing.hints.2"}) +public class HashingAssignment extends AssignmentEndpoint { + + public static final String[] SECRETS = {"secret","admin","password", "123456", "passw0rd"}; + + @RequestMapping(path="/crypto/hashing/md5",produces=MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String getMd5(HttpServletRequest request) throws NoSuchAlgorithmException { + + String md5Hash = (String) request.getSession().getAttribute("md5Hash"); + if (md5Hash == null) { + + String secret = SECRETS[new Random().nextInt(SECRETS.length)]; + + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(secret.getBytes()); + byte[] digest = md.digest(); + md5Hash = DatatypeConverter + .printHexBinary(digest).toUpperCase(); + request.getSession().setAttribute("md5Hash", md5Hash); + request.getSession().setAttribute("md5Secret", secret); + } + return md5Hash; + } + + @RequestMapping(path="/crypto/hashing/sha256",produces=MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String getSha256(HttpServletRequest request) throws NoSuchAlgorithmException { + + String sha256 = (String) request.getSession().getAttribute("sha256"); + if (sha256 == null) { + String secret = SECRETS[new Random().nextInt(SECRETS.length)]; + sha256 = getHash(secret, "SHA-256"); + request.getSession().setAttribute("sha256Hash", sha256); + request.getSession().setAttribute("sha256Secret", secret); + } + return sha256; + } + + @PostMapping("/crypto/hashing") + @ResponseBody + public AttackResult completed(HttpServletRequest request, @RequestParam String answer_pwd1, @RequestParam String answer_pwd2) { + + String md5Secret = (String) request.getSession().getAttribute("md5Secret"); + String sha256Secret = (String) request.getSession().getAttribute("sha256Secret"); + + if (answer_pwd1!=null && answer_pwd2 !=null) { + if (answer_pwd1.equals(md5Secret) + && answer_pwd2.equals(sha256Secret)) { + return success(this) + .feedback("crypto-hashing.success") + .build(); + } else if (answer_pwd1.equals(md5Secret) + || answer_pwd2.equals(sha256Secret)) { + return failed(this).feedback("crypto-hashing.oneok").build(); + } + } + return failed(this).feedback("crypto-hashing.empty").build(); + } + + public static String getHash(String secret, String algorithm) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance(algorithm); + md.update(secret.getBytes()); + byte[] digest = md.digest(); + return DatatypeConverter + .printHexBinary(digest).toUpperCase(); + } + +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/IDORLogin.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/IDORLogin.java new file mode 100644 index 00000000..7e0dd7ff --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/IDORLogin.java @@ -0,0 +1,75 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.idor; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; + +import org.owasp.webgoat.session.UserSessionData; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@AssignmentHints({"idor.hints.idor_login"}) +public class IDORLogin extends AssignmentEndpoint { + + private Map> idorUserInfo = new HashMap<>(); + + public void initIDORInfo() { + + idorUserInfo.put("tom", new HashMap()); + idorUserInfo.get("tom").put("password", "cat"); + idorUserInfo.get("tom").put("id", "2342384"); + idorUserInfo.get("tom").put("color", "yellow"); + idorUserInfo.get("tom").put("size", "small"); + + idorUserInfo.put("bill", new HashMap()); + idorUserInfo.get("bill").put("password", "buffalo"); + idorUserInfo.get("bill").put("id", "2342388"); + idorUserInfo.get("bill").put("color", "brown"); + idorUserInfo.get("bill").put("size", "large"); + + } + + @PostMapping("/IDOR/login") + @ResponseBody + public AttackResult completed(@RequestParam String username, @RequestParam String password) { + initIDORInfo(); + UserSessionData userSessionData = getUserSessionData(); + + if (idorUserInfo.containsKey(username)) { + if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) { + userSessionData.setValue("idor-authenticated-as", username); + userSessionData.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id")); + return success(this).feedback("idor.login.success").feedbackArgs(username).build(); + } else { + return failed(this).feedback("idor.login.failure").build(); + } + } else { + return failed(this).feedback("idor.login.failure").build(); + } + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTFinalEndpointTest.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTFinalEndpointTest.java new file mode 100644 index 00000000..c79a1356 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTFinalEndpointTest.java @@ -0,0 +1,98 @@ +package org.owasp.webgoat.jwt; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.owasp.webgoat.plugins.LessonTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import io.jsonwebtoken.Jwt; +import io.jsonwebtoken.Jwts; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +public class JWTFinalEndpointTest extends LessonTest { + + private static final String TOKEN_JERRY = "eyJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTNTEyIn0.eyJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImVtYWlsIjoiamVycnlAd2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IkplcnJ5In0.xBc5FFwaOcuxjdr_VJ16n8Jb7vScuaZulNTl66F2MWF1aBe47QsUosvbjWGORNcMPiPNwnMu1Yb0WZVNrp2ZXA"; + + @Autowired + private JWT jwt; + + @Autowired + private JWTFinalEndpoint jwtFinalEndpoint; + + @Before + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(jwt); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + @Test + public void solveAssignment() throws Exception { + String key = "deletingTom"; + Map claims = new HashMap<>(); + claims.put("username", "Tom"); + String token = Jwts.builder() + .setHeaderParam("kid", "hacked' UNION select '" + key + "' from INFORMATION_SCHEMA.SYSTEM_USERS --") + .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10))) + .setClaims(claims) + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, key) + .compact(); + mockMvc.perform(MockMvcRequestBuilders.post("/JWT/final/delete") + .param("token", token) + .content("")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } + + @Test + public void withJerrysKeyShouldNotSolveAssignment() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/JWT/final/delete") + .param("token", TOKEN_JERRY) + .content("")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-final-jerry-account")))); + } + + @Test + public void shouldNotBeAbleToBypassWithSimpleToken() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/JWT/final/delete") + .param("token", ".eyJ1c2VybmFtZSI6IlRvbSJ9.") + .content("")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); + } + + @Test + @SneakyThrows + public void testJWTTestTools() { + + //JWTFinalEndpoint jwtFinalEndpoint = new JWTFinalEndpoint(null); + String jsonHeader = "{\"alg\":\"HS256\"}"; + String jsonPayload = "{\"iss\":\"OWASP\"}"; + String jsonSecret = "secret"; + String jwtToken = jwtFinalEndpoint.encode(jsonHeader, jsonPayload, jsonSecret).replace(":", "") + .replace("encodedHeader", "").replace("encodedPayload", "").replace("encodedSignature", "") + .replace("{", "").replace("}", "").replace("\"", "").replace(",", "."); + + Jwt jwt = Jwts.parser().setSigningKey(jsonSecret).parse(jwtToken); + String revert = jwtFinalEndpoint.decode(jwtToken); + //System.out.println("revert: "+revert); + + } +} \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTRefreshEndpoint.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTRefreshEndpoint.java new file mode 100644 index 00000000..39b63c32 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTRefreshEndpoint.java @@ -0,0 +1,133 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.jwt; + +import io.jsonwebtoken.*; +import org.apache.commons.lang3.RandomStringUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +import static org.springframework.http.ResponseEntity.ok; + +/** + * @author nbaars + * @since 4/23/17. + */ +@RestController +@AssignmentHints({"jwt-refresh-hint1", "jwt-refresh-hint2", "jwt-refresh-hint3", "jwt-refresh-hint4"}) +public class JWTRefreshEndpoint extends AssignmentEndpoint { + + public static final String PASSWORD = "bm5nhSkxCXZkKRy4"; + private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4"; + private static final List validRefreshTokens = new ArrayList<>(); + + @PostMapping(value = "/JWT/refresh/login", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public ResponseEntity follow(@RequestBody(required = false) Map json) { + if (json == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + String user = (String) json.get("user"); + String password = (String) json.get("password"); + + if ("Jerry".equalsIgnoreCase(user) && PASSWORD.equals(password)) { + return ok(createNewTokens(user)); + } + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + + private Map createNewTokens(String user) { + Map claims = new HashMap<>(); + claims.put("admin", "false"); + claims.put("user", user); + String token = Jwts.builder() + .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10))) + .setClaims(claims) + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD) + .compact(); + Map tokenJson = new HashMap<>(); + String refreshToken = RandomStringUtils.randomAlphabetic(20); + validRefreshTokens.add(refreshToken); + tokenJson.put("access_token", token); + tokenJson.put("refresh_token", refreshToken); + return tokenJson; + } + + @PostMapping("/JWT/refresh/checkout") + @ResponseBody + public ResponseEntity checkout(@RequestHeader(value = "Authorization", required = false) String token) { + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + try { + Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", "")); + Claims claims = (Claims) jwt.getBody(); + String user = (String) claims.get("user"); + if ("Tom".equals(user)) { + return ok(success(this).build()); + } + return ok(failed(this).feedback("jwt-refresh-not-tom").feedbackArgs(user).build()); + } catch (ExpiredJwtException e) { + return ok(failed(this).output(e.getMessage()).build()); + } catch (JwtException e) { + return ok(failed(this).feedback("jwt-invalid-token").build()); + } + } + + @PostMapping("/JWT/refresh/newToken") + @ResponseBody + public ResponseEntity newToken(@RequestHeader(value = "Authorization", required = false) String token, + @RequestBody(required = false) Map json) { + if (token == null || json == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + + String user; + String refreshToken; + try { + Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", "")); + user = (String) jwt.getBody().get("user"); + refreshToken = (String) json.get("refresh_token"); + } catch (ExpiredJwtException e) { + user = (String) e.getClaims().get("user"); + refreshToken = (String) json.get("refresh_token"); + } + + if (user == null || refreshToken == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } else if (validRefreshTokens.contains(refreshToken)) { + validRefreshTokens.remove(refreshToken); + return ok(createNewTokens(user)); + } else { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTVotesEndpoint.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTVotesEndpoint.java new file mode 100644 index 00000000..cf36551b --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/JWTVotesEndpoint.java @@ -0,0 +1,177 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwt; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.impl.TextCodec; +import org.apache.commons.lang3.StringUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.jwt.votes.Views; +import org.owasp.webgoat.jwt.votes.Vote; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.MappingJacksonValue; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.PostConstruct; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Comparator.comparingLong; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + +/** + * @author nbaars + * @since 4/23/17. + */ +@RestController +@AssignmentHints({"jwt-change-token-hint1", "jwt-change-token-hint2", "jwt-change-token-hint3", "jwt-change-token-hint4", "jwt-change-token-hint5"}) +public class JWTVotesEndpoint extends AssignmentEndpoint { + + public static final String JWT_PASSWORD = TextCodec.BASE64.encode("victory"); + private static String validUsers = "TomJerrySylvester"; + + private static int totalVotes = 38929; + private Map votes = new HashMap<>(); + + @PostConstruct + public void initVotes() { + votes.put("Admin lost password", new Vote("Admin lost password", + "In this challenge you will need to help the admin and find the password in order to login", + "challenge1-small.png", "challenge1.png", 36000, totalVotes)); + votes.put("Vote for your favourite", + new Vote("Vote for your favourite", + "In this challenge ...", + "challenge5-small.png", "challenge5.png", 30000, totalVotes)); + votes.put("Get it for free", + new Vote("Get it for free", + "The objective for this challenge is to buy a Samsung phone for free.", + "challenge2-small.png", "challenge2.png", 20000, totalVotes)); + votes.put("Photo comments", + new Vote("Photo comments", + "n this challenge you can comment on the photo you will need to find the flag somewhere.", + "challenge3-small.png", "challenge3.png", 10000, totalVotes)); + } + + @GetMapping("/JWT/votings/login") + public void login(@RequestParam("user") String user, HttpServletResponse response) { + if (validUsers.contains(user)) { + Claims claims = Jwts.claims().setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(10)))); + claims.put("admin", "false"); + claims.put("user", user); + String token = Jwts.builder() + .setClaims(claims) + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD) + .compact(); + Cookie cookie = new Cookie("access_token", token); + response.addCookie(cookie); + response.setStatus(HttpStatus.OK.value()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + } else { + Cookie cookie = new Cookie("access_token", ""); + response.addCookie(cookie); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + } + } + + @GetMapping("/JWT/votings") + @ResponseBody + public MappingJacksonValue getVotes(@CookieValue(value = "access_token", required = false) String accessToken) { + MappingJacksonValue value = new MappingJacksonValue(votes.values().stream().sorted(comparingLong(Vote::getAverage).reversed()).collect(toList())); + if (StringUtils.isEmpty(accessToken)) { + value.setSerializationView(Views.GuestView.class); + } else { + try { + Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken); + Claims claims = (Claims) jwt.getBody(); + String user = (String) claims.get("user"); + if ("Guest".equals(user) || !validUsers.contains(user)) { + value.setSerializationView(Views.GuestView.class); + } else { + value.setSerializationView(Views.UserView.class); + } + } catch (JwtException e) { + value.setSerializationView(Views.GuestView.class); + } + } + return value; + } + + @PostMapping(value = "/JWT/votings/{title}") + @ResponseBody + @ResponseStatus(HttpStatus.ACCEPTED) + public ResponseEntity vote(@PathVariable String title, @CookieValue(value = "access_token", required = false) String accessToken) { + if (StringUtils.isEmpty(accessToken)) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } else { + try { + Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken); + Claims claims = (Claims) jwt.getBody(); + String user = (String) claims.get("user"); + if (!validUsers.contains(user)) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } else { + ofNullable(votes.get(title)).ifPresent(v -> v.incrementNumberOfVotes(totalVotes)); + return ResponseEntity.accepted().build(); + } + } catch (JwtException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + } + } + + @PostMapping("/JWT/votings") + @ResponseBody + public AttackResult resetVotes(@CookieValue(value = "access_token", required = false) String accessToken) { + if (StringUtils.isEmpty(accessToken)) { + return failed(this).feedback("jwt-invalid-token").build(); + } else { + try { + Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken); + Claims claims = (Claims) jwt.getBody(); + boolean isAdmin = Boolean.valueOf((String) claims.get("admin")); + if (!isAdmin) { + return failed(this).feedback("jwt-only-admin").build(); + } else { + votes.values().forEach(vote -> vote.reset()); + return success(this).build(); + } + } catch (JwtException e) { + return failed(this).feedback("jwt-invalid-token").output(e.toString()).build(); + } + } + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/LICENSE.txt b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/LICENSE.txt new file mode 100644 index 00000000..573d2b4e --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/LICENSE.txt @@ -0,0 +1,19 @@ +This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + +Copyright (c) 2002 - 2019 Bruce Mayhew + +This program is free software; you can redistribute it and/or modify it under the terms of the +GNU General Public License as published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + +Getting Source ============== + +Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SSRFTask2.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SSRFTask2.java new file mode 100644 index 00000000..533fd791 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SSRFTask2.java @@ -0,0 +1,82 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.ssrf; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; + + +@RestController +@AssignmentHints({"ssrf.hint3"}) +public class SSRFTask2 extends AssignmentEndpoint { + + @PostMapping("/SSRF/task2") + @ResponseBody + public AttackResult completed(@RequestParam String url) { + return furBall(url); + } + + protected AttackResult furBall(String url) { + try { + StringBuffer html = new StringBuffer(); + + if (url.matches("http://ifconfig.pro")) { + URL u = new URL(url); + URLConnection urlConnection = u.openConnection(); + BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + String inputLine; + + while ((inputLine = in.readLine()) != null) { + html.append(inputLine); + } + in.close(); + + return success(this) + .feedback("ssrf.success") + .output(html.toString()) + .build(); + } else { + html.append("\"image"); + return failed(this) + .feedback("ssrf.failure") + .output(html.toString()) + .build(); + } + } catch (Exception e) { + e.printStackTrace(); + return failed(this) + .output(e.getMessage()) + .build(); + } + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson4.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson4.java new file mode 100644 index 00000000..e0e8286f --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson4.java @@ -0,0 +1,77 @@ + +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.introduction; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.sql.DataSource; +import java.sql.*; + +import static java.sql.ResultSet.*; + + +@RestController +@AssignmentHints(value = {"SqlStringInjectionHint4-1", "SqlStringInjectionHint4-2", "SqlStringInjectionHint4-3"}) +public class SqlInjectionLesson4 extends AssignmentEndpoint { + + private final DataSource dataSource; + + public SqlInjectionLesson4(DataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/SqlInjection/attack4") + @ResponseBody + public AttackResult completed(@RequestParam String query) { + return injectableQuery(query); + } + + protected AttackResult injectableQuery(String query) { + try (Connection connection = dataSource.getConnection()) { + try (Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) { + statement.executeUpdate(query); + connection.commit(); + ResultSet results = statement.executeQuery("SELECT phone from employees;"); + StringBuffer output = new StringBuffer(); + // user completes lesson if column phone exists + if (results.first()) { + output.append(""); + return success(this).output(output.toString()).build(); + } else { + return failed(this).output(output.toString()).build(); + } + } catch (SQLException sqle) { + return failed(this).output(sqle.getMessage()).build(); + } + } catch (Exception e) { + return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build(); + } + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson6a.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson6a.java new file mode 100644 index 00000000..7220fee5 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson6a.java @@ -0,0 +1,99 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.advanced; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.sql_injection.introduction.SqlInjectionLesson5a; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.sql.DataSource; +import java.sql.*; + + +@RestController +@AssignmentHints(value = {"SqlStringInjectionHint-advanced-6a-1", "SqlStringInjectionHint-advanced-6a-2", "SqlStringInjectionHint-advanced-6a-3", + "SqlStringInjectionHint-advanced-6a-4"}) +public class SqlInjectionLesson6a extends AssignmentEndpoint { + + private final DataSource dataSource; + + public SqlInjectionLesson6a(DataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/SqlInjectionAdvanced/attack6a") + @ResponseBody + public AttackResult completed(@RequestParam String userid_6a) { + return injectableQuery(userid_6a); + // The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- + } + + public AttackResult injectableQuery(String accountName) { + String query = ""; + try (Connection connection = dataSource.getConnection()) { + boolean usedUnion = true; + query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; + //Check if Union is used + if (!accountName.matches("(?i)(^[^-/*;)]*)(\\s*)UNION(.*$)")) { + usedUnion = false; + } + try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY)) { + ResultSet results = statement.executeQuery(query); + + if ((results != null) && (results.first())) { + ResultSetMetaData resultsMetaData = results.getMetaData(); + StringBuffer output = new StringBuffer(); + + output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); + + String appendingWhenSucceded; + if (usedUnion) + appendingWhenSucceded = "Well done! Can you also figure out a solution, by appending a new Sql Statement?"; + else + appendingWhenSucceded = "Well done! Can you also figure out a solution, by using a UNION?"; + results.last(); + + if (output.toString().contains("dave") && output.toString().contains("passW0rD")) { + output.append(appendingWhenSucceded); + return success(this).feedback("sql-injection.advanced.6a.success").feedbackArgs(output.toString()).output(" Your query was: " + query).build(); + } else { + return failed(this).output(output.toString() + "
Your query was: " + query).build(); + } + } else { + return failed(this).feedback("sql-injection.advanced.6a.no.results").output(" Your query was: " + query).build(); + } + } catch (SQLException sqle) { + return failed(this).output(sqle.getMessage() + "
Your query was: " + query).build(); + } + } catch (Exception e) { + e.printStackTrace(); + return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + query).build(); + } + } +} \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson9.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson9.java new file mode 100644 index 00000000..2fd36428 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlInjectionLesson9.java @@ -0,0 +1,110 @@ + +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.introduction; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.hsqldb.jdbc.JDBCResultSet.CONCUR_UPDATABLE; +import static org.hsqldb.jdbc.JDBCResultSet.TYPE_SCROLL_SENSITIVE; + +@RestController +@AssignmentHints(value = {"SqlStringInjectionHint.9.1", "SqlStringInjectionHint.9.2", "SqlStringInjectionHint.9.3", "SqlStringInjectionHint.9.4", "SqlStringInjectionHint.9.5"}) +public class SqlInjectionLesson9 extends AssignmentEndpoint { + + private final DataSource dataSource; + + public SqlInjectionLesson9(DataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/SqlInjection/attack9") + @ResponseBody + public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { + return injectableQueryIntegrity(name, auth_tan); + } + + protected AttackResult injectableQueryIntegrity(String name, String auth_tan) { + StringBuffer output = new StringBuffer(); + String query = "SELECT * FROM employees WHERE last_name = '" + name + "' AND auth_tan = '" + auth_tan + "'"; + try (Connection connection = dataSource.getConnection()) { + try { + Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); + SqlInjectionLesson8.log(connection, query); + ResultSet results = statement.executeQuery(query); + var test = results.getRow() != 0; + if (results.getStatement() != null) { + if (results.first()) { + output.append(SqlInjectionLesson8.generateTable(results)); + } else { + // no results + return failed(this).feedback("sql-injection.8.no.results").build(); + } + } + } catch (SQLException e) { + System.err.println(e.getMessage()); + return failed(this).feedback("sql-injection.error").output("
").build(); + } + + return checkSalaryRanking(connection, output); + + } catch (Exception e) { + System.err.println(e.getMessage()); + return failed(this).feedback("sql-injection.error").output("
").build(); + } + } + + private AttackResult checkSalaryRanking(Connection connection, StringBuffer output) { + try { + String query = "SELECT * FROM employees ORDER BY salary DESC"; + try (Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); + ) { + ResultSet results = statement.executeQuery(query); + + results.first(); + // user completes lesson if John Smith is the first in the list + if ((results.getString(2).equals("John")) && (results.getString(3).equals("Smith"))) { + output.append(SqlInjectionLesson8.generateTable(results)); + return success(this).feedback("sql-injection.9.success").output(output.toString()).build(); + } else { + return failed(this).feedback("sql-injection.9.one").output(output.toString()).build(); + } + } + } catch (SQLException e) { + return failed(this).feedback("sql-injection.error").output("
").build(); + } + } + +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlOnlyInputValidation.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlOnlyInputValidation.java new file mode 100644 index 00000000..0bfa5baf --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/SqlOnlyInputValidation.java @@ -0,0 +1,55 @@ + +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.mitigation; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.sql_injection.advanced.SqlInjectionLesson6a; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@AssignmentHints(value = {"SqlOnlyInputValidation-1", "SqlOnlyInputValidation-2", "SqlOnlyInputValidation-3"}) +public class SqlOnlyInputValidation extends AssignmentEndpoint { + + private final SqlInjectionLesson6a lesson6a; + + public SqlOnlyInputValidation(SqlInjectionLesson6a lesson6a) { + this.lesson6a = lesson6a; + } + + @PostMapping("/SqlOnlyInputValidation/attack") + @ResponseBody + public AttackResult attack(@RequestParam("userid_sql_only_input_validation") String userId) { + if (userId.contains(" ")) { + return failed(this).feedback("SqlOnlyInputValidation-failed").build(); + } + AttackResult attackResult = lesson6a.injectableQuery(userId); + return new AttackResult(attackResult.isLessonCompleted(), attackResult.getFeedback(), attackResult.getOutput(), getClass().getSimpleName(), true); + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/StoredXssComments.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/StoredXssComments.java new file mode 100644 index 00000000..af96c4fe --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/StoredXssComments.java @@ -0,0 +1,105 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.xss.stored; + +import com.beust.jcommander.internal.Lists; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.session.WebSession; +import org.owasp.webgoat.xss.Comment; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import static org.springframework.http.MediaType.ALL_VALUE; + +import java.io.IOException; +import java.util.*; + + +@RestController +public class StoredXssComments extends AssignmentEndpoint { + + @Autowired + private WebSession webSession; + private static DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd, HH:mm:ss"); + + private static final Map> userComments = new HashMap<>(); + private static final List comments = new ArrayList<>(); + private static final String phoneHomeString = ""; + + + static { + comments.add(new Comment("secUriTy", DateTime.now().toString(fmt), "Comment for Unit Testing")); + comments.add(new Comment("webgoat", DateTime.now().toString(fmt), "This comment is safe")); + comments.add(new Comment("guest", DateTime.now().toString(fmt), "This one is safe too.")); + comments.add(new Comment("guest", DateTime.now().toString(fmt), "Can you post a comment, calling webgoat.customjs.phoneHome() ?")); + } + + //TODO This assignment seems not to be in use in the UI + @GetMapping(path = "/CrossSiteScriptingStored/stored-xss", produces = MediaType.APPLICATION_JSON_VALUE, consumes = ALL_VALUE) + @ResponseBody + public Collection retrieveComments() { + List allComments = Lists.newArrayList(); + Collection newComments = userComments.get(webSession.getUserName()); + allComments.addAll(comments); + if (newComments != null) { + allComments.addAll(newComments); + } + Collections.reverse(allComments); + return allComments; + } + + //TODO This assignment seems not to be in use in the UI + @PostMapping("/CrossSiteScriptingStored/stored-xss") + @ResponseBody + public AttackResult createNewComment(@RequestBody String commentStr) { + Comment comment = parseJson(commentStr); + + List comments = userComments.getOrDefault(webSession.getUserName(), new ArrayList<>()); + comment.setDateTime(DateTime.now().toString(fmt)); + comment.setUser(webSession.getUserName()); + + comments.add(comment); + userComments.put(webSession.getUserName(), comments); + + if (comment.getText().contains(phoneHomeString)) { + return (success(this).feedback("xss-stored-comment-success").build()); + } else { + return (failed(this).feedback("xss-stored-comment-failure").build()); + } + } + + private Comment parseJson(String comment) { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(comment, Comment.class); + } catch (IOException e) { + return new Comment(); + } + } +} \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/UserValidatorTest.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/UserValidatorTest.java new file mode 100644 index 00000000..f88a50e4 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/UserValidatorTest.java @@ -0,0 +1,61 @@ +package org.owasp.webgoat.users; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.Errors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class UserValidatorTest { + + @Mock + private UserRepository userRepository; + + @Test + public void passwordsShouldMatch() { + UserForm userForm = new UserForm(); + userForm.setAgree("true"); + userForm.setUsername("test1234"); + userForm.setPassword("test1234"); + userForm.setMatchingPassword("test1234"); + Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); + new UserValidator(userRepository).validate(userForm, errors); + assertFalse(errors.hasErrors()); + } + + @Test + public void shouldGiveErrorWhenPasswordsDoNotMatch() { + UserForm userForm = new UserForm(); + userForm.setAgree("true"); + userForm.setUsername("test1234"); + userForm.setPassword("test12345"); + userForm.setMatchingPassword("test1234"); + Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); + new UserValidator(userRepository).validate(userForm, errors); + assertTrue(errors.hasErrors()); + assertThat(errors.getFieldError("matchingPassword").getCode()).isEqualTo("password.diff"); + } + + @Test + public void shouldGiveErrorWhenUserAlreadyExists() { + UserForm userForm = new UserForm(); + userForm.setAgree("true"); + userForm.setUsername("test12345"); + userForm.setPassword("test12345"); + userForm.setMatchingPassword("test12345"); + when(userRepository.findByUsername(anyString())).thenReturn(new WebGoatUser("test1245", "password")); + Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); + new UserValidator(userRepository).validate(userForm, errors); + assertTrue(errors.hasErrors()); + assertThat(errors.getFieldError("username").getCode()).isEqualTo("username.duplicate"); + } + +} \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/Users.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/Users.java new file mode 100644 index 00000000..291ee9c8 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/Users.java @@ -0,0 +1,117 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.missing_ac; + +import org.owasp.webgoat.session.UserSessionData; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; + +public class Users { + + private UserSessionData userSessionData; + private DataSource dataSource; + + public Users(UserSessionData userSessionData, DataSource dataSource) { + this.userSessionData = userSessionData; + this.dataSource = dataSource; + } + + @GetMapping(produces = {"application/json"}) + @ResponseBody + protected HashMap getUsers() { + + try (Connection connection = dataSource.getConnection()) { + String query = "SELECT * FROM user_data"; + + try { + Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + ResultSet results = statement.executeQuery(query); + HashMap allUsersMap = new HashMap(); + + if ((results != null) && (results.first() == true)) { + while (results.next()) { + HashMap userMap = new HashMap<>(); + userMap.put("first", results.getString(1)); + userMap.put("last", results.getString(2)); + userMap.put("cc", results.getString(3)); + userMap.put("ccType", results.getString(4)); + userMap.put("cookie", results.getString(5)); + userMap.put("loginCount", Integer.toString(results.getInt(6))); + allUsersMap.put(results.getInt(0), userMap); + } + userSessionData.setValue("allUsers", allUsersMap); + return allUsersMap; + + } + } catch (SQLException sqle) { + sqle.printStackTrace(); + HashMap errMap = new HashMap() {{ + put("err", sqle.getErrorCode() + "::" + sqle.getMessage()); + }}; + + return new HashMap() {{ + put(0, errMap); + }}; + } catch (Exception e) { + e.printStackTrace(); + HashMap errMap = new HashMap() {{ + put("err", e.getMessage() + "::" + e.getCause()); + }}; + e.printStackTrace(); + return new HashMap() {{ + put(0, errMap); + }}; + + + } finally { + try { + if (connection != null) { + connection.close(); + } + } catch (SQLException sqle) { + sqle.printStackTrace(); + } + } + + } catch (Exception e) { + e.printStackTrace(); + HashMap errMap = new HashMap() {{ + put("err", e.getMessage() + "::" + e.getCause()); + }}; + e.printStackTrace(); + return new HashMap<>() {{ + put(0, errMap); + }}; + + } + return null; + } +} diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/WebSecurityConfig.java b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/WebSecurityConfig.java new file mode 100644 index 00000000..79a1b075 --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/WebSecurityConfig.java @@ -0,0 +1,100 @@ +/** + * ************************************************************************************************ + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + *

+ * Copyright (c) 2002 - 20014 Bruce Mayhew + *

+ * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + *

+ * Getting Source ============== + *

+ * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software + * projects. + *

+ * + * @author WebGoat + * @version $Id: $Id + * @since December 12, 2015 + */ + +package org.owasp.webgoat; + +import lombok.AllArgsConstructor; +import org.owasp.webgoat.users.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; + +/** + * Security configuration for WebGoat. + */ +@Configuration +@AllArgsConstructor +@EnableWebSecurity +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + private final UserService userDetailsService; + + @Override + protected void configure(HttpSecurity http) throws Exception { + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry security = http + .authorizeRequests() + .antMatchers("/css/**", "/images/**", "/js/**", "fonts/**", "/plugins/**", "/registration", "/register.mvc").permitAll() + .anyRequest().authenticated(); + security.and() + .formLogin() + .loginPage("/login") + .defaultSuccessUrl("/welcome.mvc", true) + .usernameParameter("username") + .passwordParameter("password") + .permitAll(); + security.and() + .logout().deleteCookies("JSESSIONID").invalidateHttpSession(true); + security.and().csrf().disable(); + + http.headers().cacheControl().disable(); + http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService); //.passwordEncoder(bCryptPasswordEncoder()); + } + + @Bean + @Override + public UserDetailsService userDetailsServiceBean() throws Exception { + return userDetailsService; + } + + @Override + @Bean + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + + @SuppressWarnings("deprecation") + @Bean + public NoOpPasswordEncoder passwordEncoder() { + return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); + } +} \ No newline at end of file diff --git a/tests/fixtures/sarif_convertor/shallow_sast_webgoat/jquery.form.js b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/jquery.form.js new file mode 100644 index 00000000..bced6cbe --- /dev/null +++ b/tests/fixtures/sarif_convertor/shallow_sast_webgoat/jquery.form.js @@ -0,0 +1,1367 @@ +/*! + * jQuery Form Plugin + * version: 3.51.0-2014.06.20 + * Requires jQuery v1.5 or later + * Copyright (c) 2014 M. Alsup + * Examples and documentation at: http://malsup.com/jquery/form/ + * Project repository: https://github.com/malsup/form + * Dual licensed under the MIT and GPL licenses. + * https://github.com/malsup/form#copyright-and-license + */ +/*global ActiveXObject */ + +// AMD support +(function (factory) { + "use strict"; + if (typeof define === "function" && define.amd) { + // using AMD; register as anon module + define(["jquery"], factory); + } else { + // no AMD; invoke directly + factory(typeof jQuery != "undefined" ? jQuery : window.Zepto); + } +})(function ($) { + "use strict"; + + /* + Usage Note: + ----------- + Do not use both ajaxSubmit and ajaxForm on the same form. These + functions are mutually exclusive. Use ajaxSubmit if you want + to bind your own submit handler to the form. For example, + + $(document).ready(function() { + $('#myForm').on('submit', function(e) { + e.preventDefault(); // <-- important + $(this).ajaxSubmit({ + target: '#output' + }); + }); + }); + + Use ajaxForm when you want the plugin to manage all the event binding + for you. For example, + + $(document).ready(function() { + $('#myForm').ajaxForm({ + target: '#output' + }); + }); + + You can also use ajaxForm with delegation (requires jQuery v1.7+), so the + form does not have to exist when you invoke ajaxForm: + + $('#myForm').ajaxForm({ + delegation: true, + target: '#output' + }); + + When using ajaxForm, the ajaxSubmit function will be invoked for you + at the appropriate time. +*/ + + /** + * Feature detection + */ + var feature = {}; + feature.fileapi = $("").get(0).files !== undefined; + feature.formdata = window.FormData !== undefined; + + var hasProp = !!$.fn.prop; + + // attr2 uses prop when it can but checks the return type for + // an expected string. this accounts for the case where a form + // contains inputs with names like "action" or "method"; in those + // cases "prop" returns the element + $.fn.attr2 = function () { + if (!hasProp) { + return this.attr.apply(this, arguments); + } + var val = this.prop.apply(this, arguments); + if ((val && val.jquery) || typeof val === "string") { + return val; + } + return this.attr.apply(this, arguments); + }; + + /** + * ajaxSubmit() provides a mechanism for immediately submitting + * an HTML form using AJAX. + */ + $.fn.ajaxSubmit = function (options) { + /*jshint scripturl:true */ + + // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) + if (!this.length) { + log("ajaxSubmit: skipping submit process - no element selected"); + return this; + } + + var method, + action, + url, + $form = this; + + if (typeof options == "function") { + options = { success: options }; + } else if (options === undefined) { + options = {}; + } + + method = options.type || this.attr2("method"); + action = options.url || this.attr2("action"); + + url = typeof action === "string" ? $.trim(action) : ""; + url = url || window.location.href || ""; + if (url) { + // clean url (don't include hash vaue) + url = (url.match(/^([^#]+)/) || [])[1]; + } + + options = $.extend( + true, + { + url: url, + success: $.ajaxSettings.success, + type: method || $.ajaxSettings.type, + iframeSrc: /^https/i.test(window.location.href || "") + ? "javascript:false" + : "about:blank", + }, + options + ); + + // hook for manipulating the form data before it is extracted; + // convenient for use with rich editors like tinyMCE or FCKEditor + var veto = {}; + this.trigger("form-pre-serialize", [this, options, veto]); + if (veto.veto) { + log("ajaxSubmit: submit vetoed via form-pre-serialize trigger"); + return this; + } + + // provide opportunity to alter form data before it is serialized + if ( + options.beforeSerialize && + options.beforeSerialize(this, options) === false + ) { + log("ajaxSubmit: submit aborted via beforeSerialize callback"); + return this; + } + + var traditional = options.traditional; + if (traditional === undefined) { + traditional = $.ajaxSettings.traditional; + } + + var elements = []; + var qx, + a = this.formToArray(options.semantic, elements); + if (options.data) { + options.extraData = options.data; + qx = $.param(options.data, traditional); + } + + // give pre-submit callback an opportunity to abort the submit + if ( + options.beforeSubmit && + options.beforeSubmit(a, this, options) === false + ) { + log("ajaxSubmit: submit aborted via beforeSubmit callback"); + return this; + } + + // fire vetoable 'validate' event + this.trigger("form-submit-validate", [a, this, options, veto]); + if (veto.veto) { + log("ajaxSubmit: submit vetoed via form-submit-validate trigger"); + return this; + } + + var q = $.param(a, traditional); + if (qx) { + q = q ? q + "&" + qx : qx; + } + if (options.type.toUpperCase() == "GET") { + options.url += (options.url.indexOf("?") >= 0 ? "&" : "?") + q; + options.data = null; // data is null for 'get' + } else { + options.data = q; // data is the query string for 'post' + } + + var callbacks = []; + if (options.resetForm) { + callbacks.push(function () { + $form.resetForm(); + }); + } + if (options.clearForm) { + callbacks.push(function () { + $form.clearForm(options.includeHidden); + }); + } + + // perform a load on the target only if dataType is not provided + if (!options.dataType && options.target) { + var oldSuccess = options.success || function () {}; + callbacks.push(function (data) { + var fn = options.replaceTarget ? "replaceWith" : "html"; + $(options.target)[fn](data).each(oldSuccess, arguments); + }); + } else if (options.success) { + callbacks.push(options.success); + } + + options.success = function (data, status, xhr) { + // jQuery 1.4+ passes xhr as 3rd arg + var context = options.context || this; // jQuery 1.4+ supports scope context + for (var i = 0, max = callbacks.length; i < max; i++) { + callbacks[i].apply(context, [data, status, xhr || $form, $form]); + } + }; + + if (options.error) { + var oldError = options.error; + options.error = function (xhr, status, error) { + var context = options.context || this; + oldError.apply(context, [xhr, status, error, $form]); + }; + } + + if (options.complete) { + var oldComplete = options.complete; + options.complete = function (xhr, status) { + var context = options.context || this; + oldComplete.apply(context, [xhr, status, $form]); + }; + } + + // are there files to upload? + + // [value] (issue #113), also see comment: + // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 + var fileInputs = $("input[type=file]:enabled", this).filter(function () { + return $(this).val() !== ""; + }); + + var hasFileInputs = fileInputs.length > 0; + var mp = "multipart/form-data"; + var multipart = $form.attr("enctype") == mp || $form.attr("encoding") == mp; + + var fileAPI = feature.fileapi && feature.formdata; + log("fileAPI :" + fileAPI); + var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; + + var jqxhr; + + // options.iframe allows user to force iframe mode + // 06-NOV-09: now defaulting to iframe mode if file input is detected + if (options.iframe !== false && (options.iframe || shouldUseFrame)) { + // hack to fix Safari hang (thanks to Tim Molendijk for this) + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d + if (options.closeKeepAlive) { + $.get(options.closeKeepAlive, function () { + jqxhr = fileUploadIframe(a); + }); + } else { + jqxhr = fileUploadIframe(a); + } + } else if ((hasFileInputs || multipart) && fileAPI) { + jqxhr = fileUploadXhr(a); + } else { + jqxhr = $.ajax(options); + } + + $form.removeData("jqxhr").data("jqxhr", jqxhr); + + // clear element array + for (var k = 0; k < elements.length; k++) { + elements[k] = null; + } + + // fire 'notify' event + this.trigger("form-submit-notify", [this, options]); + return this; + + // utility fn for deep serialization + function deepSerialize(extraData) { + var serialized = $.param(extraData, options.traditional).split("&"); + var len = serialized.length; + var result = []; + var i, part; + for (i = 0; i < len; i++) { + // #252; undo param space replacement + serialized[i] = serialized[i].replace(/\+/g, " "); + part = serialized[i].split("="); + // #278; use array instead of object storage, favoring array serializations + result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); + } + return result; + } + + // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) + function fileUploadXhr(a) { + var formdata = new FormData(); + + for (var i = 0; i < a.length; i++) { + formdata.append(a[i].name, a[i].value); + } + + if (options.extraData) { + var serializedData = deepSerialize(options.extraData); + for (i = 0; i < serializedData.length; i++) { + if (serializedData[i]) { + formdata.append(serializedData[i][0], serializedData[i][1]); + } + } + } + + options.data = null; + + var s = $.extend(true, {}, $.ajaxSettings, options, { + contentType: false, + processData: false, + cache: false, + type: method || "POST", + }); + + if (options.uploadProgress) { + // workaround because jqXHR does not expose upload property + s.xhr = function () { + var xhr = $.ajaxSettings.xhr(); + if (xhr.upload) { + xhr.upload.addEventListener( + "progress", + function (event) { + var percent = 0; + var position = + event.loaded || + event.position; /*event.position is deprecated*/ + var total = event.total; + if (event.lengthComputable) { + percent = Math.ceil((position / total) * 100); + } + options.uploadProgress(event, position, total, percent); + }, + false + ); + } + return xhr; + }; + } + + s.data = null; + var beforeSend = s.beforeSend; + s.beforeSend = function (xhr, o) { + //Send FormData() provided by user + if (options.formData) { + o.data = options.formData; + } else { + o.data = formdata; + } + if (beforeSend) { + beforeSend.call(this, xhr, o); + } + }; + return $.ajax(s); + } + + // private function for handling file uploads (hat tip to YAHOO!) + function fileUploadIframe(a) { + var form = $form[0], + el, + i, + s, + g, + id, + $io, + io, + xhr, + sub, + n, + timedOut, + timeoutHandle; + var deferred = $.Deferred(); + + // #341 + deferred.abort = function (status) { + xhr.abort(status); + }; + + if (a) { + // ensure that every serialized input is still enabled + for (i = 0; i < elements.length; i++) { + el = $(elements[i]); + if (hasProp) { + el.prop("disabled", false); + } else { + el.removeAttr("disabled"); + } + } + } + + s = $.extend(true, {}, $.ajaxSettings, options); + s.context = s.context || s; + id = "jqFormIO" + new Date().getTime(); + if (s.iframeTarget) { + $io = $(s.iframeTarget); + n = $io.attr2("name"); + if (!n) { + $io.attr2("name", id); + } else { + id = n; + } + } else { + $io = $('