Yii2 Security

List of Best Practices in order to get full security among Yii2 Applications.

Consider these following points in order to get best security in your Yii2 Application.

Filter Input:

Use yii2 form wherever possible

If you are not using yii2 form then validate the input by yourself.

$sortBy = $_GET['sort']; if (!in_array($sortBy, ['title', 'created_at', 'status'])) { thrownewException('Invalid sort value.'); } 1 2 3 4 5 $sortBy = $_GET [ 'sort' ] ; if ( ! in_array ( $sortBy , [ 'title' , 'created_at' , 'status' ] ) ) { thrownewException ( 'Invalid sort value.' ) ; }

File Upload Validation:

File extension validation

File mime type validation

Avoiding SQL injection:

SQL injection happens when query text is formed by concatenating unescaped (Used direct input variables in sql queries).

->where('status=:status', [':status' => $status]) ->all();

OR

$userIDs = $connection ->createCommand('SELECT id FROM user where status=:status') ->bindValues([':status' => $status]); 1 2 3 $userIDs = $connection -> createCommand ( 'SELECT id FROM user where status=:status' ) -> bindValues ( [ ':status' = > $status ] ) ;

Avoiding XSS is quite easy in Yii. There are generally two cases: You want data to be outputted as plain text. If all you need is plain text then escaping is as easy as the following:

<?= \ yii \ helpers \ Html:: encode ( $username ) ?> You want data to be outputted as HTML .

If it should be HTML we could get some help from HtmlPurifier:

<?= \ yii \ helpers \ HtmlPurifier:: process ( $description ) ?>

is quite easy in Yii. There are generally two cases:

Avoiding CSRF(Cross-site request forgery):

In order to avoid CSRF you should always: Follow HTTP specification i.e. GET should not change application state. Keep Yii CSRF protection enabled. Avoiding debug info and tools in production: Never run production applications with YII_DEBUG set to true in your php.



Avoiding Host-header attacks:

If the webserver is configured to serve independent of the value of the Hostheader, this information may not be reliable and may be faked by the user sending the HTTP request. In such situations you should either fix your webserver configuration to serve the site only for specified host names or explicitly set or filter the value by setting the hostInfo property of the request application component.

If you don’t have access to the server configuration, you can setup yii\filters\HostControl filter at application level in order to protect against such kind of attack:

// Web Application configuration file return [ 'as hostControl' => [ 'class' => 'yii\filters\HostControl', 'allowedHosts' => [ 'example.com', '*.example.com', ], 'fallbackHostInfo' => 'https://example.com', ], // ... ]; 1 2 3 4 5 6 7 8 9 10 11 12 // Web Application configuration file return [ 'as hostControl' = > [ 'class' = > 'yii\filters\HostControl' , 'allowedHosts' = > [ 'example.com' , '*.example.com' , ] , 'fallbackHostInfo' = > 'https://example.com' , ] , // ... ] ;

Avoid File exposure:

Deny access to everything except web

Headers Protection:

Follow these article below to set security headers

https://www.asepms.com/wordpress/hardening-http-security-headers-htaccess.html

https://scotthelme.co.uk/hardening-your-http-response-headers/

My .htaccess setting are:

<IfModule mod_headers.c> Header unset Server Header always unset X-Powered-By Header unset X-Powered-By Header unset X-CF-Powered-By Header unset X-Mod-Pagespeed Header unset X-Pingback Header set Strict-Transport-Security "max-age=10886400; includeSubDomains; preload" env=HTTPS Header set X-Frame-Options "ALLOW-FROM https://www.googletagmanager.com/" Header always set X-Xss-Protection "1; mode=block" Header always set X-Content-Type-Options "nosniff" Header set Referrer-Policy: strict-origin-when-cross-origin </IfModule> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 < IfModule mod_headers . c > Header unset Server Header always unset X - Powered - By Header unset X - Powered - By Header unset X - CF - Powered - By Header unset X - Mod - Pagespeed Header unset X - Pingback Header set Strict - Transport - Security "max-age=10886400; includeSubDomains; preload" env = HTTPS Header set X - Frame - Options "ALLOW-FROM https://www.googletagmanager.com/" Header always set X - Xss - Protection "1; mode=block" Header always set X - Content - Type - Options "nosniff" Header set Referrer - Policy : strict - origin - when - cross - origin < / IfModule >

We can test security header of any site using this link: https://securityheaders.io/