Mitigation Strategy: Strict Output Encoding with Yii2's Html
Helper
-
Description:
- Identify all output points: Go through every view file (
.php
files inviews/
) and identify where data is being output. - Apply context-aware encoding using
yii\helpers\Html
:Html::encode()
: For general HTML text content.Html::encode($data, ENT_QUOTES, 'UTF-8')
: For HTML attributes.Html::jsEncode()
: For data embedded within JavaScript code.Html::cssEncode()
: For data embedded within CSS styles.
- Never bypass encoding: Do not use raw PHP
echo
with user-supplied data without using theHtml
helper. - Rich Text Editor Configuration (if using a Yii2 wrapper/extension): If using a rich text editor through a Yii2 extension or wrapper, configure the Yii2 component to ensure it sanitizes output and limits allowed HTML tags. This often involves configuring the extension's properties, not the editor's native configuration directly.
- Content Security Policy (CSP) using Yii2's Response Component: Implement CSP headers using Yii2's response component. Example (in
config/web.php
):'response' => [ 'class' => 'yii\web\Response', 'on beforeSend' => function ($event) { $response = $event->sender; $response->headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline';"); // VERY restrictive, adjust! }, ],
- Identify all output points: Go through every view file (
-
Threats Mitigated:
- Cross-Site Scripting (XSS) (Severity: High): Yii2's
Html
helper provides the core mechanism for preventing XSS. - HTML Injection (Severity: Medium): Again, the
Html
helper is the primary defense.
- Cross-Site Scripting (XSS) (Severity: High): Yii2's
-
Impact:
- XSS: Risk significantly reduced (80-90%) with consistent use of Yii2's encoding functions.
- HTML Injection: Risk significantly reduced (90%).
-
Currently Implemented:
Html::encode()
is used in most view files.
-
Missing Implementation:
Html::jsEncode()
andHtml::cssEncode()
are not consistently used.- CSP implementation is basic and needs refinement.
- Yii2 wrapper for CKEditor is not configured to restrict allowed HTML tags (assuming a Yii2 wrapper is used).
Mitigation Strategy: Enable and Enforce Yii2's CSRF Protection
-
Description:
- Global Enablement (Yii2 Config): In
config/web.php
, ensure therequest
component hasenableCsrfValidation
set totrue
:'request' => [ 'enableCsrfValidation' => true, // ... other settings ... ],
ActiveForm
Usage: Use Yii2'sActiveForm
widget for all forms. This automatically handles CSRF token inclusion.- Manual Forms (Include Yii2's CSRF Token): If creating forms manually, include the CSRF token using Yii2's helpers:
<input type="hidden" name="<?= Yii::$app->request->csrfParam; ?>" value="<?= Yii::$app->request->getCsrfToken(); ?>">
- AJAX Requests (Use Yii2's CSRF Token): Include the CSRF token in AJAX requests, preferably using Yii2's JavaScript helper:
$.ajax({ url: '...', type: 'POST', data: { _csrf: yii.getCsrfToken(), // Yii2's JavaScript helper // ... other data ... }, success: function(data) { ... } });
- Per-Action Disabling (Discouraged, but Yii2-Specific): If absolutely necessary, disable CSRF for a specific action using the
$enableCsrfValidation
property of the Yii2 controller or action:$this->enableCsrfValidation = false;
(within the controller action). Document the reason.
- Global Enablement (Yii2 Config): In
-
Threats Mitigated:
- Cross-Site Request Forgery (CSRF) (Severity: High): Yii2's built-in CSRF protection is the primary mitigation.
-
Impact:
- CSRF: Risk reduced significantly (95%+) when Yii2's CSRF protection is properly implemented.
-
Currently Implemented:
enableCsrfValidation
istrue
globally.ActiveForm
is used for most forms.
-
Missing Implementation:
- Some older forms are manual and lack the Yii2-generated CSRF token.
- AJAX requests in one module don't use
yii.getCsrfToken()
.
Mitigation Strategy: Parameterized Queries with Yii2's Active Record and Query Builder
-
Description:
- Active Record/Query Builder: Use Yii2's Active Record or Query Builder for all database interactions. These automatically handle parameterization. Example (Active Record):
Example (Query Builder):
$user = User::findOne(['username' => $username]); // Parameterized by Yii2
$users = (new \yii\db\Query()) ->select(['id', 'username']) ->from('user') ->where(['status' => 1]) ->andWhere(['like', 'username', $search]) // Parameterized 'like' by Yii2 ->all();
- Avoid
rawSql()
(or use Yii2's Parameterization): Do not useyii\db\Command::rawSql()
unless unavoidable. If you must, use Yii2's parameter binding:$command = Yii::$app->db->createCommand("SELECT * FROM user WHERE id = :id"); $command->bindValue(':id', $id); // Yii2's parameter binding $user = $command->queryOne();
- Input Validation using Yii2 Model Rules: Use Yii2's model validation rules to validate all user input before it's used in database queries (even though Active Record/Query Builder parameterize, this is defense-in-depth). Example (in the
User
model):public function rules() { return [ [['username', 'email'], 'required'], ['username', 'string', 'min' => 4, 'max' => 255], ['email', 'email'], // ... other rules ... ]; }
- Active Record/Query Builder: Use Yii2's Active Record or Query Builder for all database interactions. These automatically handle parameterization. Example (Active Record):
-
Threats Mitigated:
- SQL Injection (Severity: Critical): Yii2's Active Record and Query Builder, when used correctly, are the primary defense against SQL injection.
- Data Type Mismatches (Severity: Low): Yii2's model validation rules help prevent this.
-
Impact:
- SQL Injection: Risk reduced to near zero (99%+) with consistent use of Yii2's parameterized query mechanisms.
- Data Type Mismatches: Risk reduced significantly.
-
Currently Implemented:
- Active Record is used for most database interactions.
- Basic model validation rules are in place.
-
Missing Implementation:
- A few older parts use
rawSql()
without Yii2's parameter binding. - Input validation is not comprehensive; some fields lack Yii2 validation rules.
- A few older parts use
Mitigation Strategy: Secure Mass Assignment with Yii2 Scenarios
-
Description:
- Define Scenarios (Yii2 Models): In each Active Record model, define scenarios for different operations (e.g.,
create
,update
). safeAttributes
(Yii2 Models): Within each scenario, specify thesafeAttributes
that are allowed to be mass-assigned using Yii2's scenario mechanism. Example (in theUser
model):const SCENARIO_CREATE = 'create'; const SCENARIO_UPDATE = 'update'; public function scenarios() { $scenarios = parent::scenarios(); $scenarios[self::SCENARIO_CREATE] = ['username', 'email', 'password']; $scenarios[self::SCENARIO_UPDATE] = ['username', 'email']; // Password not allowed return $scenarios; }
- Use
$model->load()
with Scenario (Yii2 Controller Logic): When loading data from user input, always specify the scenario:$model = new User(); if ($model->load(Yii::$app->request->post(), self::SCENARIO_CREATE) && $model->save()) { // ... }
- Avoid Direct Assignment: Do not bypass Yii2's scenario mechanism by using
$model->attributes = $_POST['ModelName'];
. - Regular Review: Periodically review model scenarios to ensure they are up-to-date.
- Define Scenarios (Yii2 Models): In each Active Record model, define scenarios for different operations (e.g.,
-
Threats Mitigated:
- Mass Assignment (Severity: Medium): Yii2's scenario mechanism is the primary defense.
-
Impact:
- Mass Assignment: Risk reduced significantly (90%+) with proper use of Yii2 scenarios.
-
Currently Implemented:
- Scenarios are defined in some models.
-
Missing Implementation:
- Scenarios are not consistently defined across all models.
- Some controllers bypass Yii2's scenarios with direct assignment.
Mitigation Strategy: Disable Debug Mode and Configure Yii2's Error Handler
-
Description:
- Production Settings (Yii2 Bootstrap): In
web/index.php
, ensureYII_DEBUG
isfalse
andYII_ENV
is'prod'
:defined('YII_DEBUG') or define('YII_DEBUG', false); defined('YII_ENV') or define('YII_ENV', 'prod');
- Error Handler Configuration (Yii2 Config): In
config/web.php
, configure theerrorHandler
component:'errorHandler' => [ 'errorAction' => 'site/error', // Use a custom Yii2 error action ],
- Custom Error Action (Yii2 Controller): Create a custom error action (e.g.,
controllers/SiteController.php
) to display a generic message without revealing sensitive details. Use Yii2's logging:public function actionError() { $exception = Yii::$app->errorHandler->exception; if ($exception !== null) { // Log using Yii2's logging framework Yii::error($exception->getMessage(), 'application'); return $this->render('error', ['message' => 'An error occurred.']); } }
- Logging (Yii2 Config): Configure Yii2's logging framework (
config/web.php
) to log errors to a secure file:'log' => [ 'targets' => [ [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning'], 'logFile' => '@runtime/logs/app.log', // Secure location ], ], ],
- Production Settings (Yii2 Bootstrap): In
-
Threats Mitigated:
- Information Disclosure (Severity: Medium): Yii2's debug mode and default error handling can expose sensitive information.
-
Impact:
- Information Disclosure: Risk significantly reduced (95%+) by disabling Yii2's debug mode and configuring the error handler.
-
Currently Implemented:
YII_DEBUG
andYII_ENV
are set correctly.- Basic Yii2 error logging is configured.
-
Missing Implementation:
- A custom Yii2 error action is not implemented; the default Yii2 error page is still shown (though without debug info).
Mitigation Strategy: Secure File Uploads with Yii2's UploadedFile
and FileValidator
-
Description:
UploadedFile
(Yii2): Use Yii2'sUploadedFile
class to handle file uploads.FileValidator
(Yii2 Model Rules): Use Yii2'sFileValidator
in your model rules:public function rules() { return [ [['image'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg, gif', 'maxSize' => 1024 * 1024 * 2, 'checkExtensionByMimeType' => true], // 2MB, check MIME type ]; }
- Storage Outside Web Root (Using Yii2 Aliases): Store files outside the web root using Yii2 aliases:
$uploadPath = Yii::getAlias('@app/uploads'); // Outside web root, defined using Yii2's alias system if (!is_dir($uploadPath)) { mkdir($uploadPath, 0777, true); } $model->image->saveAs($uploadPath . '/' . $uniqueFilename); // Use Yii2's saveAs() method
- Unique Filenames (with Yii2 Helpers): Generate unique filenames (e.g., using
uniqid()
or a Yii2 helper function).
-
Threats Mitigated:
- File Upload Vulnerabilities (Severity: High): Yii2's
UploadedFile
andFileValidator
provide the core mechanisms. - Directory Traversal (Severity: High): Storing files outside the web root (using Yii2 aliases) is crucial.
- File Upload Vulnerabilities (Severity: High): Yii2's
-
Impact:
- File Upload Vulnerabilities: Risk significantly reduced (90%+) with proper use of Yii2's upload handling.
- Directory Traversal: Risk eliminated by using Yii2 aliases to store files outside the web root.
-
Currently Implemented:
UploadedFile
is used.- Basic
FileValidator
rules are in place.
-
Missing Implementation:
- Files are stored within the web root (not using Yii2 aliases correctly).
checkExtensionByMimeType
is not set totrue
in theFileValidator
rules.- Unique filenames are not consistently generated using Yii2 helpers.
Mitigation Strategy: Secure Session Management with Yii2's Session Component
-
Description:
- Session Component Configuration (Yii2 Config): In
config/web.php
, configure thesession
component:'session' => [ 'class' => 'yii\web\Session', 'cookieParams' => [ 'httpOnly' => true, 'secure' => true, // MUST be true if using HTTPS 'path' => '/', ], 'useStrictMode' => true, 'useTransparentSessionID' => false, 'timeout' => 1800, // 30 minutes // Consider using a different Yii2 session storage: // 'class' => 'yii\web\DbSession', // Yii2's database session // 'class' => 'yii\redis\Session', // Yii2's Redis session ],
- Session Regeneration (Yii2 Controller Logic): Regenerate the session ID after login using Yii2's
regenerateID()
:public function actionLogin() { // ... login logic ... if ($user->login()) { Yii::$app->session->regenerateID(); // Yii2's session regeneration return $this->goHome(); } }
- Logout (using Yii2's User component): Ensure that the logout action properly destroys the session using Yii2's
logout()
method:public function actionLogout() { Yii::$app->user->logout(); // Use Yii2's logout method return $this->goHome(); }
- Session Component Configuration (Yii2 Config): In
-
Threats Mitigated:
- Session Hijacking (Severity: High): Yii2's session component settings (
httpOnly
,secure
) are crucial. - Session Fixation (Severity: High): Yii2's
regenerateID()
is the primary defense.
- Session Hijacking (Severity: High): Yii2's session component settings (
-
Impact:
- Session Hijacking: Risk significantly reduced with correct Yii2 session component settings.
- Session Fixation: Risk eliminated by using Yii2's
regenerateID()
.
-
Currently Implemented:
httpOnly
is set totrue
in the Yii2 session configuration.
-
Missing Implementation:
secure
isfalse
(should betrue
with HTTPS).useStrictMode
anduseTransparentSessionID
are not set in the Yii2 session configuration.- Session ID is not regenerated after login using Yii2's
regenerateID()
. - The default file-based session storage is used; consider Yii2's
DbSession
orRedisSession
.