9.8 | Analyzing source code | Security engine custom configuration

On this page

Security engine custom configuration

Security Engine Custom Configuration is available as part of the Enterprise Edition and above.

The security engine tracks the path that data follows through your code. It detects when data that's potentially manipulated by a malicious user reaches a sensitive piece of code where an attack can occur.

Those potentially malicious data are also called tainted data because they are tainted by user inputs.

SonarQube's security engine already knows a lot of APIs that are potential sources or targets of attack. While we do our best to identify publicly available APIs, we can't know everything about your homemade frameworks particularly when it comes to sanitizing your data. Because of this, SonarQube allows you to customize the security engine to add your own sources, sanitizers, passthroughs, and sinks (see the Elements section below for more on these elements).

For example, you may want to:

  • Add a source to add support for a framework that SonarQube doesn't cover out of the box.
  • Use a custom sanitizer to tell the security engine that all data going through sanitizers should be considered safe. This allows you to remove false positives and tailor the security engine to your company.

Rules

You can customize elements for Java, PHP, C#, and Python rules in the security engine. Click the languages below to expand a list of customizable rules for that language:

Java
  • S2076: OS command injection
  • S2078: LDAP injection
  • S2083: Path traversal injection
  • S2091: XPath injection
  • S2631: RegExp injection
  • S3649: SQL injection
  • S5131: XSS
  • S5135: Deserialization injection
  • S5144: Server-side request forgery (SSRF)
  • S5145: Log injection
  • S5146: Open redirect
  • S5147: NoSQL injection
  • S5883: OS command injection
  • S5334: Code injection
  • S6096: Zip slip
  • S6173: Reflection injection
  • S6287: HTTP session fixation
  • S6384: Component intent redirection
  • S6390: Thread suspension denial of service
  • S6398: JSON injection
  • S6399: XML injection
PHP
  • S2076: OS command injection
  • S2078: LDAP injection
  • S2083: Path traversal injection
  • S2091: XPath injection
  • S2631: RegExp injection
  • S3649: SQL injection
  • S5131: XSS
  • S5135: Deserialization injection
  • S5144: Server-side request forgery (SSRF)
  • S5145: Log injection
  • S5146: Open redirect
  • S5334: Code injection
  • S5335: Include injection
  • S5883: OS command injection
  • S6173: Reflection injection
  • S6287: HTTP session fixation
C#
Python

Elements

You can add the following elements to your custom configuration:

  • Source – Where you get user data. You should always consider user data tainted and vulnerable to injection attacks. Example: Calling HttpServletRequest#getParam("foo") will return tainted content.
  • Sanitizer – Finds and removes malicious content from one or more potentially tainted arguments. Example: DatabaseUtils#sqlEscapeString(String str) returns a modified version of str where characters used in an SQL injection attack are removed.
  • Validator - Marks one or more arguments as safe from malicious content. Example: String#matches(String str) can be used to verify that str does not contain any content which may be used in an injection attack.
  • Passthrough – Allows you to keep track of tainted data sent to a library outside the current function. When you pass a tainted value to a library function outside the current function, SonarQube automatically assumes it's being passed to a sanitizer. If the tainted data isn't being passed to a sanitizer, you can set up a passthrough to keep track of the data.
  • Sink – A piece of code that can perform a security-sensitive task. Data should not contain any malicious content once it reaches a sink. Example: Running an SQL query with java.sql.Statement#execute.

MethodId

All custom configurations rely on the accuracy of the methodIds provided. The methodId format differs for each language. Click the language you're using below for more information on the format for that language.

Creating your custom configuration JSON file

You need to add your custom configurations to SonarQube using a JSON file. You can apply your custom configuration to a specific project or to all of your projects at the global level in SonarQube:

  • Project level – go to Project Settings > General Settings > SAST Engine and add your JSON file to the JAVA/PHP/C#/Python custom configuration field.
  • Global level – go to Administration > General Settings > SAST Engine and add your JSON file to the JAVA/PHP/C#/Python custom configuration field.

See the following section for more information on formatting your JSON file.

Configuration file format

Your JSON file should include the rule you're adding a custom element to, the element you are customizing, and the methodId for each element. Each language needs a separate JSON file but can contain multiple rules. You may use the special rule key common to apply the given configuration to all the rules. Click your language below to expand an example of a JSON file to help you understand the expected format.

Java JSON file example
{
  "S3649": {
    "sources": [
      {
        "methodId": "my.package.ServerRequest#getQuery()Ljava/lang/String;"
      }
    ],
    "sanitizers": [
      {
        "methodId": "my.package.StringUtils#stringReplace(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
        "args": [
          2 
        ]
      }
    ],
    "validators": [
      {
        "methodId": "my.package.StringUtils#equals(Ljava/lang/String;)Z",
        "args": [
          1
        ]
      }
    ],
    "passthroughs": [
      {
        "methodId": "my.package.RawUrl#<init>(Ljava/lang/String;)V",
        "isWhitelist": true,
        "args": [
          1
        ]
      }
    ],
    "sinks": [
      {
        "methodId": "my.package.MySql#query(Ljava/lang/String;)V",
        "args": [
          1
        ]
      },
      {
        "methodId": "my.package.SqlStatement#execute",
        "isMethodPrefix": true,
        "args": [
          0,
          1
        ]
      },
      {
        "methodId": "my.package.SqlStatement#run(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "S5131": {
    "sources": [
      {
        "methodId": "my.package.ServerRequest#getQueryString()Ljava/lang/String;"
      }
    ],
    "sinks": [
      {
        "methodId": "my.package.Server#write(",
        "isMethodPrefix": true,
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "common": {
    "sources": [
      {
        "methodId": "my.package.Input#getUserInput()Ljava/lang/String;"
      }
    ]
  }
}

The args is the index of the parameter that can receive a tainted variable. Index starts:

  • 1 for a function call.
  • 0 for a method call, index 0 being the current instance (this). The args field must be a non-empty array of non-negative integers, and it is a mandatory field for sanitizers and validators.
PHP JSON file example
{
  "S3649": {
    "sources": [
      {
        "methodId": "My\\Namespace\\ClassName\\ServerRequest::getQuery"
      }
    ],
    "sanitizers": [
      {
        "methodId": "str_replace",
        "args": [
          3
        ]
      }
    ],
    "validators": [
      {
        "methodId": "My\\Namespace\\Validator\\inArray::isValid",
        "args": [
          1
        ]
      }
    ],
    "passthroughs": [
      {
        "methodId": "My\\Namespace\\RawUrl::RawUrl",
        "isWhitelist": true,
        "args": [
          1
        ]
      }
    ],
    "sinks": [
      {
        "methodId": "mysql_query",
        "args": [
          1
        ]
      },
     {
        "methodId": "My\\Namespace\\SqlStatement::execute",
        "isMethodPrefix": true,
        "args": [
          0,
          1
        ]
      },
      {
        "methodId": "My\\Namespace\\SqlStatement::run",
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "S5131": {
    "sources": [
      {
        "methodId": "My\\Namespace\\ClassName\\ServerRequest::getQueryString"
      }
    ],
    "sinks": [
      {
        "methodId": "My\\Namespace\\ClassName\\Server::write",
        "isMethodPrefix": true,
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "common": {
    "sources": [
      {
        "methodId": "My\\Namespace\\ClassName\\Input::getUserInput"
      }
    ]
  }
}

The args is the index of the parameter that can receive a tainted variable. Index starts:

  • 1 for a function call.
  • 0 for a method call, index 0 being the current instance (this). The args field must be a non-empty array of non-negative integers, and it is a mandatory field for sanitizers and validators.
C# JSON file example
{
  "S3649": {
    "sources": [
      {
        "methodId": "My.Namespace.ServerRequest.GetQuery()"
      }
    ],
    "sanitizers": [
      {
        "methodId": "My.Namespace.StringUtils.StringReplace(string, string)",
        "args": [
          0
        ]
      }
    ],
    "validators": [
      {
        "methodId": "My.Namespace.StringUtils.Regex.Matches(string)",
        "args": [
          0
        ]
      }
    ],
    "passthroughs": [
      {
        "methodId": "My.Namespace.RawUrl.RawUrl(string)",
        "isWhitelist": true,
        "args": [
          1
        ]
      }
    ],
    "sinks": [
      {
        "methodId": "My.Namespace.MySql.Query(string)",
        "args": [
          1
        ]
      },
      {
        "methodId": "My.Namespace.SqlStatement.Execute",
        "isMethodPrefix": true,
        "args": [
          0,
          1
        ]
      },
      {
        "methodId": "My.Namespace.SqlStatement.Run(string, string, string)",
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "S5131": {
    "sources": [
      {
        "$comment": "The following method id is a getter on the 'QueryString' property",
        "methodId": "My.Namespace.ServerRequest.QueryString.get"
      }
    ],
    "sinks": [
      {
        "methodId": "My.Namespace.Server.Write(",
        "isMethodPrefix": true,
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "common": {
    "sources": [
      {
        "methodId": "My.Namespace.Input.GetUserInput()"
      }
    ]
  }
}

The args is the index of the parameter that can receive a tainted variable. Index starts:

  • 1 for a function call.
  • 0 for a method call, index 0 being the current instance (this). The args field must be a non-empty array of non-negative integers, and it is a mandatory field for sanitizers and validators.
Python JSON file example
{
  "S3649": {
    "sources": [
      {
        "methodId": "my.namespace.ServerRequest.get_query"
      }
    ],
    "sanitizers": [
      {
        "methodId": "str_replace",
        "args": [
          1
        ]
      }
    ],
    "validators": [
      {
        "methodId": "my.namespace.regex.matches",
        "args": [
          1
        ]
      }
    ],
    "passthroughs": [
      {
        "methodId": "my.namespace.RawUrl",
        "isWhitelist": true,
        "args": [
          1
        ]
      }
    ],
    "sinks": [
      {
        "methodId": "mysql_query",
        "args": [
          1
        ]
      },
      {
        "methodId": "my.namespace.SqlStatement.execute",
        "isMethodPrefix": true,
        "args": [
          0,
          1
        ]
      },
      {
        "methodId": "my.namespace.SqlStatement.run",
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "S5131": {
    "sources": [
      {
        "methodId": "my.namespace.ServerRequest.get_query_string"
      }
    ],
    "sinks": [
      {
        "methodId": "my.namespace.Server.write(",
        "isMethodPrefix": true,
        "interval": {
          "fromIndex": 1
        }
      }
    ]
  },
  "common": {
    "sources": [
      {
        "methodId": "my.namespace.Input.get_input"
      }
    ]
  }
}

The args is the index of the parameter that can receive a tainted variable. Index starts:

  • 1 for a function call.
  • 0 for a method call, index 0 being the current instance (this). The args field must be a non-empty array of non-negative integers, and it is a mandatory field for sanitizers and validators.

(Deprecated) Customizing through analysis parameters

To customize the SonarQube security engine, you can feed security configuration data through parameters given to the SonarScanners. To do this, you should provide JSON files with the value of the new analysis parameters.

The parameters should use the following syntax:

sonar.security.[ConfigType].[RuleRepository].[RuleKey]=[FileName]

The ConfigType value can be one of the following:

  • sources
  • sanitizers
  • passthroughs
  • sinks

The RuleRepository value can be one of the following:

  • javasecurity: if you want to customize the Java Security Engine
  • phpsecurity: if you want to customize the PHP Security Engine
  • roslyn.sonaranalyzer.security.cs: if you want to customize the C# Security Engine
  • pythonsecurity: if you want to customize the Python Security Engine

The RuleKey value should be one of the values shown in the Rules section above.

JSON formatting example

Configuration is provided using JSON files. Click the heading below to expand an example PHP JSON file to help you understand the expected format.

JSON File Format Example for PHP
{
  "sources": [
    {
      "methodId": "My\\Namespace\\ClassName\\ServerRequest::getQuery"
    }
  ],
  "sanitizers": [
    {
      "methodId": "str_replace",
      "args": [
        3
      ]
    }
  ],
  "validators": [
    {
     "methodId": "My\\Namespace\\Validator\\inArray::isValid",
     "args": [
        1
      ]
    }
  ],
 "passthroughs": [
    {
      "methodId": "rawurldecode",
      "args": [
        1
      ]
    }
  ],
  "sinks": [
    {
      "methodId": "mysql_query",
      "args": [
        1
      ]
    },
    {
      "methodId": "My\\Namespace\\SqlStatement::execute",
      "isMethodPrefix": true, // this is to say that all the methods starting with execute on the SqlStatement object will be considered
      "args": [
        0,
        1
      ]
    },
    {
      "methodId": "My\\Namespace\\SqlStatement::run",
      "interval": {
        "fromIndex": 1 // every parameter from the number 1 will be considered
      }
    }
  ]  
}

The args is the index of the parameter that can receive a tainted variable. Index starts:

  • 1 for a function call.
  • 0 for a method call, index 0 being the current instance (this) . The args field must be a non-empty array of non-negative integers, and it is a mandatory field for sanitizers and validators.

Deactivating the core configuration

You can disable the core configuration per language or per rule using the following:

sonar.security.[ConfigType].[RuleRepository].noDefaultConfig=[true|false]
sonar.security.[ConfigType].[RuleRepository].[RuleKey].noDefaultConfig=[true|false]

© 2008-2024 SonarSource SA. All rights reserved. SONAR, SONARSOURCE, SONARLINT, SONARQUBE, SONARCLOUD, and CLEAN AS YOU CODE are trademarks of SonarSource SA.

Creative Commons License