Skip to content

Commit

Permalink
Update documentation for taints and global configuration (vimeo#5098)
Browse files Browse the repository at this point in the history
* [DOCS] Extend documentation on global variables configuration

* [DOCS] Synchronize meaning of @psalm-taint-source input with source code

* [DOCS] Add documentation for conditional @psalm-taint-escape

* [DOCS] Add documentation for @psalm-taint-unescape
  • Loading branch information
ohader authored and danog committed Jan 29, 2021
1 parent cf9d8f0 commit ae54b72
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 10 deletions.
40 changes: 35 additions & 5 deletions docs/running_psalm/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,13 @@ Contains a list of all the directories that Psalm should inspect. You can also s
Optional. Same format as `<projectFiles>`. Directories Psalm should load but not inspect.

#### &lt;fileExtensions&gt;
Optional. A list of extensions to search over. See [Checking non-PHP files](checking_non_php_files.md) to understand how to extend this.
Optional. A list of extensions to search over. See [Checking non-PHP files](checking_non_php_files.md) to understand how to extend this.

#### &lt;plugins&gt;
Optional. A list of `<plugin filename="path_to_plugin.php" />` entries. See the [Plugins](plugins/using_plugins.md) section for more information.
Optional. A list of `<plugin filename="path_to_plugin.php" />` entries. See the [Plugins](plugins/using_plugins.md) section for more information.

#### &lt;issueHandlers&gt;
Optional. If you don't want Psalm to complain about every single issue it finds, the issueHandler tag allows you to configure that. [Dealing with code issues](dealing_with_code_issues.md) tells you more.
Optional. If you don't want Psalm to complain about every single issue it finds, the issueHandler tag allows you to configure that. [Dealing with code issues](dealing_with_code_issues.md) tells you more.

#### &lt;mockClasses&gt;
Optional. Do you use mock classes in your tests? If you want Psalm to ignore them when checking files, include a fully-qualified path to the class with `<class name="Your\Namespace\ClassName" />`
Expand All @@ -402,17 +402,47 @@ Optional. Do you have objects with properties that cannot be determined statical
Optional. If your codebase uses classes and functions that are not visible to Psalm via reflection (e.g. if there are internal packages that your codebase relies on that are not available on the machine running Psalm), you can use stub files. Used by PhpStorm (a popular IDE) and others, stubs provide a description of classes and functions without the implementations. You can find a list of stubs for common classes [here](https://github.com/JetBrains/phpstorm-stubs). List out each file with `<file name="path/to/file.php" />`.

#### &lt;ignoreExceptions&gt;
Optional. A list of exceptions to not report for `checkForThrowsDocblock` or `checkForThrowsInGlobalScope`. If an exception has `onlyGlobalScope` set to `true`, only `checkForThrowsInGlobalScope` is ignored for that exception, e.g.
Optional. A list of exceptions to not report for `checkForThrowsDocblock` or `checkForThrowsInGlobalScope`. If an exception has `onlyGlobalScope` set to `true`, only `checkForThrowsInGlobalScope` is ignored for that exception, e.g.
```xml
<ignoreExceptions>
<class name="fully\qualified\path\Exc" onlyGlobalScope="true" />
</ignoreExceptions>
```

#### &lt;globals&gt;
Optional. If your codebase uses global variables that are accessed with the `global` keyword, you can declare their type. e.g.
Optional. If your codebase uses global variables that are accessed with the `global` keyword, you can declare their type. e.g.
```xml
<globals>
<var name="globalVariableName" type="type" />
</globals>
```

Some frameworks and libraries expose functionalities through e.g. `$GLOBALS[DB]->query($query)`.
The following configuration declares custom types for super-globals (`$GLOBALS`, `$_GET`, ...).

```xml
<globals>
<var name="$GLOBALS" type="array{DB: MyVendor\DatabaseConnection, VIEW: MyVendor\TemplateView}" />
<var name="$_GET" type="array{data: array<string, string>}" />
</globals>
```

The example above declares global variables as shown below

* `$GLOBALS`
+ `DB` of type `MyVendor\DatabaseConnection`
+ `VIEW` of type `MyVendor\TemplateView`
* `$_GET`
+ `data` e.g. like `["id" => "123", "title" => "Nice"]`

## Accessing Psalm configuration in plugins

Plugins can access or modify the global configuration in plugins using
[singleton Psalm\Config](https://github.com/vimeo/psalm/blob/master/src/Psalm/Config.php).

```php
$config = \Psalm\Config::getInstance();
if (!isset($config->globals['$GLOBALS'])) {
$config->globals['$GLOBALS'] = 'array{data: array<string, string>}';
}
```
10 changes: 7 additions & 3 deletions docs/security_analysis/annotations.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
# Security analysis annotations

## `@psalm-taint-source`
## `@psalm-taint-source <taint-type>`

See [Custom taint sources](custom_taint_sources.md#taint-source-annotation).

## `@psalm-taint-sink`
## `@psalm-taint-sink <taint-type> <param-name>`

See [Custom taint sinks](custom_taint_sinks.md).

## `@psalm-taint-escape`
## `@psalm-taint-escape <taint-type #conditional>`

See [Escaping tainted output](avoiding_false_positives.md#escaping-tainted-output).

## `@psalm-taint-unescape <taint-type>`

See [Unescaping statements](avoiding_false_negatives.md#unescaping-statements).

## `@psalm-taint-specialize`

See [Specializing taints in functions](avoiding_false_positives.md#specializing-taints-in-functions) and [Specializing taints in classes](avoiding_false_positives.md#specializing-taints-in-classes).
25 changes: 25 additions & 0 deletions docs/security_analysis/avoiding_false_negatives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Avoiding false-negatives

## Unescaping statements

Post-processing previously escaped/encoded statements can cause insecure scenarios.
`@psalm-taint-unescape <taint-type>` allows to declare those components insecure explicitly.

```php
<?php

/**
* @psalm-taint-unescape html
*/
function decode(string $str): string
{
return str_replace(
['&lt;', '&gt;', '&quot;', '&apos;'],
['<', '>', '"', '"'],
$str
);
}

$safe = htmlspecialchars($_GET['text']);
echo decode($safe);
```
25 changes: 24 additions & 1 deletion docs/security_analysis/avoiding_false_positives.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Avoiding false-positives

When you run Psalms taint analysis for the first time you may see a bunch of false-positives.
When you run Psalm's taint analysis for the first time you may see a bunch of false-positives.

Nobody likes false-positives!

Expand All @@ -26,6 +26,29 @@ function echoVar(string $str) : void {
echoVar($_GET["text"]);
```

## Conditional escaping tainted input

A slightly modified version of the previous example is using a condition to determine whether the return value
is considered secure. Only in case function argument `$escape` is true, the corresponding annotation
`@psalm-taint-escape` is applied for taint type `html` .

```php
/**
* @param string $str
* @param bool $escape
* @psalm-taint-escape ($escape is true ? 'html' : null)
*/
function processVar(string $str, bool $escape = true) : string {
if ($escape) {
$str = str_replace(['<', '>'], '', $str);
}
return $str;
}

echo processVar($_GET['text'], false); // detects tainted HTML
echo processVar($_GET['text'], true); // considered secure
```

## Specializing taints in functions

For functions, methods and classes you can use the `@psalm-taint-specialize` annotation.
Expand Down
2 changes: 1 addition & 1 deletion docs/security_analysis/custom_taint_sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ You can define your own taint sources with an annotation or a plugin.

You can use the annotation `@psalm-taint-source <taint-type>` to indicate a function or method that provides user input.

In the below example the `input` taint type is specified as a standin for the four input taints `text`, `html`, `sql` and `shell`.
In the below example the `input` taint type is specified as a standin for input taints as defined in [Psalm\Type\TaintKindGroup](https://github.com/vimeo/psalm/blob/master/src/Psalm/Type/TaintKindGroup.php).

```php
/**
Expand Down

0 comments on commit ae54b72

Please sign in to comment.