Hướng dẫn php.ini security best practices - các phương pháp hay nhất về bảo mật php.ini

Dưới đây chúng tôi sẽ xem xét các nguyên tắc bảo mật chung và mô tả cách tránh các mối đe dọa khi phát triển các ứng dụng sử dụng YII. Hầu hết các nguyên tắc này không chỉ riêng cho YII mà áp dụng cho trang web hoặc phát triển phần mềm nói chung, vì vậy bạn cũng sẽ tìm thấy các liên kết để đọc thêm về các ý tưởng chung đằng sau những ý tưởng này.

Nguyên tắc cơ bản ¶

Có hai nguyên tắc chính khi nói đến bảo mật cho dù ứng dụng nào đang được phát triển:

  1. Lọc đầu vào.
  2. Thoát ra sản lượng.

Đầu vào lọc ¶

Đầu vào bộ lọc có nghĩa là đầu vào không bao giờ được coi là an toàn và bạn nên luôn luôn kiểm tra xem giá trị bạn có thực sự là một trong những giá trị được phép. Ví dụ: nếu chúng ta biết rằng việc sắp xếp có thể được thực hiện bởi ba trường

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
4,
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
5 và
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
6 và trường có thể được cung cấp thông qua đầu vào của người dùng, tốt hơn là kiểm tra giá trị chúng ta có ngay khi chúng ta nhận được. Về mặt PHP cơ bản trông giống như sau:

$sortBy = $_GET['sort'];
if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
	throw new Exception('Invalid sort value.');
}

Trong YII, rất có thể bạn sẽ sử dụng xác thực biểu mẫu để kiểm tra giống nhau.

Đọc thêm về chủ đề:

  • https://owasp.org/www-community/vulnerabilities/Improper_Data_Validation
  • https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet

Thoát ra đầu ra ¶

Đầu ra thoát có nghĩa là tùy thuộc vào ngữ cảnh mà chúng tôi đang sử dụng dữ liệu, nó sẽ được thoát, tức là trong bối cảnh của HTML, bạn nên thoát

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
7,
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
8 và các ký tự đặc biệt giống nhau. Trong bối cảnh của JavaScript hoặc SQL, nó sẽ là tập hợp các ký tự khác nhau. Vì dễ bị lỗi để thoát khỏi mọi thứ theo cách thủ công YII cung cấp các công cụ khác nhau để thực hiện thoát khỏi các bối cảnh khác nhau.

Đọc thêm về chủ đề:

  • https://owasp.org/www-community/attacks/Command_Injection
  • https://owasp.org/www-community/attacks/Code_Injection
  • https://owasp.org/www-community/attacks/xss/

Thoát ra đầu ra ¶

Đầu ra thoát có nghĩa là tùy thuộc vào ngữ cảnh mà chúng tôi đang sử dụng dữ liệu, nó sẽ được thoát, tức là trong bối cảnh của HTML, bạn nên thoát

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
7,
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
8 và các ký tự đặc biệt giống nhau. Trong bối cảnh của JavaScript hoặc SQL, nó sẽ là tập hợp các ký tự khác nhau. Vì dễ bị lỗi để thoát khỏi mọi thứ theo cách thủ công YII cung cấp các công cụ khác nhau để thực hiện thoát khỏi các bối cảnh khác nhau.

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";

Tránh tiêm SQL ¶

SELECT * FROM user WHERE username = ''; DROP TABLE user; --'

SQL Injection xảy ra khi văn bản truy vấn được hình thành bằng cách ghép các chuỗi không được phân loại như sau:

Thay vì cung cấp kẻ tấn công tên người dùng chính xác có thể cung cấp cho các ứng dụng của bạn một cái gì đó như

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
9. Kết quả SQL sẽ như sau:

Đây là truy vấn hợp lệ sẽ tìm kiếm người dùng có tên người dùng trống và sau đó sẽ bỏ bảng

SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
0 có lẽ dẫn đến trang web bị hỏng và mất dữ liệu (bạn đã thiết lập các bản sao lưu thông thường, phải không?).

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();

Trong YII, hầu hết các truy vấn cơ sở dữ liệu xảy ra thông qua bản ghi hoạt động sử dụng đúng các câu lệnh PDO trong nội bộ. Trong trường hợp các tuyên bố đã chuẩn bị, không thể thao tác truy vấn như đã được trình bày ở trên.

function actionList($orderBy = null)
{
    if (!in_array($orderBy, ['name', 'status'])) {
        throw new BadRequestHttpException('Only name and status are allowed to order by.')
    }
    
    // ...
}

Tuy nhiên, đôi khi bạn cần truy vấn thô hoặc trình tạo truy vấn. Trong trường hợp này, bạn nên sử dụng các cách truyền dữ liệu an toàn. Nếu dữ liệu được sử dụng cho các giá trị cột, bạn sẽ ưu tiên sử dụng các câu lệnh đã chuẩn bị:

$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();

Nếu dữ liệu được sử dụng để chỉ định tên cột hoặc tên bảng, điều tốt nhất cần làm là chỉ cho phép tập hợp các giá trị được xác định trước:

Đọc thêm về chủ đề:

  • https://owasp.org/www-community/attacks/SQL_Injection

Thoát ra đầu ra ¶

Đầu ra thoát có nghĩa là tùy thuộc vào ngữ cảnh mà chúng tôi đang sử dụng dữ liệu, nó sẽ được thoát, tức là trong bối cảnh của HTML, bạn nên thoát

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
7,
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
8 và các ký tự đặc biệt giống nhau. Trong bối cảnh của JavaScript hoặc SQL, nó sẽ là tập hợp các ký tự khác nhau. Vì dễ bị lỗi để thoát khỏi mọi thứ theo cách thủ công YII cung cấp các công cụ khác nhau để thực hiện thoát khỏi các bối cảnh khác nhau.

Tránh tiêm SQL ¶

  1. SQL Injection xảy ra khi văn bản truy vấn được hình thành bằng cách ghép các chuỗi không được phân loại như sau:
  2. Thay vì cung cấp kẻ tấn công tên người dùng chính xác có thể cung cấp cho các ứng dụng của bạn một cái gì đó như
    $username = $_GET['username'];
    $sql = "SELECT * FROM user WHERE username = '$username'";
    
    9. Kết quả SQL sẽ như sau:

Đây là truy vấn hợp lệ sẽ tìm kiếm người dùng có tên người dùng trống và sau đó sẽ bỏ bảng

SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
0 có lẽ dẫn đến trang web bị hỏng và mất dữ liệu (bạn đã thiết lập các bản sao lưu thông thường, phải không?).

= \yii\helpers\Html::encode($username) ?>

Trong YII, hầu hết các truy vấn cơ sở dữ liệu xảy ra thông qua bản ghi hoạt động sử dụng đúng các câu lệnh PDO trong nội bộ. Trong trường hợp các tuyên bố đã chuẩn bị, không thể thao tác truy vấn như đã được trình bày ở trên.

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

Tuy nhiên, đôi khi bạn cần truy vấn thô hoặc trình tạo truy vấn. Trong trường hợp này, bạn nên sử dụng các cách truyền dữ liệu an toàn. Nếu dữ liệu được sử dụng cho các giá trị cột, bạn sẽ ưu tiên sử dụng các câu lệnh đã chuẩn bị:

Đọc thêm về chủ đề:

  • https://owasp.org/www-community/attacks/xss/

Thoát ra đầu ra ¶

Đầu ra thoát có nghĩa là tùy thuộc vào ngữ cảnh mà chúng tôi đang sử dụng dữ liệu, nó sẽ được thoát, tức là trong bối cảnh của HTML, bạn nên thoát

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
7,
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
8 và các ký tự đặc biệt giống nhau. Trong bối cảnh của JavaScript hoặc SQL, nó sẽ là tập hợp các ký tự khác nhau. Vì dễ bị lỗi để thoát khỏi mọi thứ theo cách thủ công YII cung cấp các công cụ khác nhau để thực hiện thoát khỏi các bối cảnh khác nhau.

Tránh tiêm SQL ¶

Đó là ý tưởng cơ bản về cách hoạt động của một cuộc tấn công CSRF. Người ta có thể nói rằng việc đăng xuất người dùng không phải là một điều nghiêm trọng, tuy nhiên đây chỉ là một ví dụ, có nhiều điều người ta có thể làm bằng cách sử dụng phương pháp này, ví dụ như kích hoạt thanh toán hoặc thay đổi dữ liệu. Hãy tưởng tượng rằng một số trang web có URL

SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
9. Truy cập nó bằng cách sử dụng yêu cầu Get, gây ra chuyển giao $ 2000 từ tài khoản người dùng được ủy quyền sang người dùng
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
0. Chúng tôi biết rằng trình duyệt sẽ luôn gửi yêu cầu nhận được tải một hình ảnh, vì vậy chúng tôi có thể sửa đổi mã để chỉ chấp nhận các yêu cầu đăng trên URL đó. Thật không may, điều này sẽ không lưu chúng tôi, bởi vì kẻ tấn công có thể đặt một số mã JavaScript thay vì thẻ
SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
7, cho phép gửi các yêu cầu POST đến URL đó.

Vì lý do này, YII áp dụng các cơ chế bổ sung để bảo vệ chống lại các cuộc tấn công CSRF.

Để tránh CSRF, bạn nên luôn luôn:

  1. Theo dõi đặc tả HTTP, tức là không nên thay đổi trạng thái ứng dụng. Xem RFC2616 để biết thêm chi tiết.
  2. Giữ cho Yii CSRF bảo vệ được bật.

Đôi khi bạn cần vô hiệu hóa xác thực CSRF trên mỗi bộ điều khiển và/hoặc hành động. Nó có thể đạt được bằng cách đặt tài sản của nó:

namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public $enableCsrfValidation = false;

    public function actionIndex()
    {
        // CSRF validation will not be applied to this and other actions
    }

}

Để vô hiệu hóa xác thực CSRF cho mỗi hành động tùy chỉnh, bạn có thể làm:

namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public function beforeAction($action)
    {
        // ...set `$this->enableCsrfValidation` here based on some conditions...
        // call parent method that will check CSRF if such property is `true`.
        return parent::beforeAction($action);
    }
}

Vô hiệu hóa xác thực CSRF trong các hành động độc lập phải được thực hiện theo phương pháp

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
2. Không đặt mã này vào phương thức
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
3 vì nó sẽ không có hiệu lực.

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
0

Cảnh báo: Vô hiệu hóa CSRF sẽ cho phép bất kỳ trang web nào gửi yêu cầu POST đến trang web của bạn. Điều quan trọng là thực hiện xác thực thêm như kiểm tra địa chỉ IP hoặc mã thông báo bí mật trong trường hợp này.Disabling CSRF will allow any site to send POST requests to your site. It is important to implement extra validation such as checking an IP address or a secret token in this case.

Lưu ý: Vì phiên bản 2.0.21 YII hỗ trợ cài đặt cookie

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
4 (yêu cầu Php phiên bản 7.3.0 trở lên). Cài đặt cài đặt cookie
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
4 không làm cho lỗi trên vì không phải tất cả các trình duyệt đều hỗ trợ cài đặt. Xem tùy chọn Phiên và Cookies Samesite để biết thêm thông tin.
Since version 2.0.21 Yii supports the
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
4 cookie setting (requires PHP version 7.3.0 or higher). Setting the
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
4 cookie setting does not make the above obsolete since not all browsers support the setting yet. See the Sessions and Cookies sameSite option for more information.

Đọc thêm về chủ đề:

  • https://owasp.org/www-community/attacks/csrf
  • https://owasp.org/www-community/SameSite

Tránh tiếp xúc với tệp ¶

Theo mặc định, máy chủ Webroot có nghĩa là được chỉ vào thư mục

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
6 trong đó
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
7. Trong trường hợp môi trường lưu trữ được chia sẻ, có thể không thể đạt được, vì vậy chúng tôi sẽ kết thúc với tất cả các mã, cấu hình và nhật ký trong máy chủ Webroot.

Nếu đó là trường hợp đừng quên từ chối quyền truy cập vào mọi thứ ngoại trừ

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
6. Nếu nó không thể được thực hiện, hãy xem xét việc lưu trữ ứng dụng của bạn ở nơi khác.

Trong chế độ gỡ lỗi, YII cho thấy các lỗi khá dài dòng, chắc chắn rất hữu ích cho sự phát triển. Vấn đề là các lỗi dài dòng này cũng tiện dụng cho kẻ tấn công vì chúng có thể tiết lộ cấu trúc cơ sở dữ liệu, giá trị cấu hình và các phần của mã của bạn. Không bao giờ chạy các ứng dụng sản xuất với

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
9 được đặt thành
function actionList($orderBy = null)
{
    if (!in_array($orderBy, ['name', 'status'])) {
        throw new BadRequestHttpException('Only name and status are allowed to order by.')
    }
    
    // ...
}
0 trong
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
7 của bạn.

Bạn không bao giờ nên kích hoạt Gii hoặc thanh công cụ gỡ lỗi trong sản xuất. Nó có thể được sử dụng để có được thông tin về cấu trúc cơ sở dữ liệu, mã và chỉ cần viết lại mã với những gì được tạo bởi GII.

Thanh công cụ gỡ lỗi nên tránh trong sản xuất trừ khi thực sự cần thiết. Nó phơi bày tất cả các chi tiết ứng dụng và cấu hình có thể. Nếu bạn hoàn toàn cần nó, hãy kiểm tra hai lần rằng quyền truy cập chỉ được giới hạn đúng cho IP của bạn.

Đọc thêm về chủ đề:

  • https://owasp.org/www-project-.net/articles/Exception_Handling.md
  • Tránh tiếp xúc với tệp ¶

Theo mặc định, máy chủ Webroot có nghĩa là được chỉ vào thư mục // query builder $userIDs = (new Query()) ->select('id') ->from('user') ->where('status=:status', [':status' => $status]) ->all(); // DAO $userIDs = $connection ->createCommand('SELECT id FROM user where status=:status') ->bindValues([':status' => $status]) ->queryColumn(); 6 trong đó // query builder $userIDs = (new Query()) ->select('id') ->from('user') ->where('status=:status', [':status' => $status]) ->all(); // DAO $userIDs = $connection ->createCommand('SELECT id FROM user where status=:status') ->bindValues([':status' => $status]) ->queryColumn(); 7. Trong trường hợp môi trường lưu trữ được chia sẻ, có thể không thể đạt được, vì vậy chúng tôi sẽ kết thúc với tất cả các mã, cấu hình và nhật ký trong máy chủ Webroot.

Nếu đó là trường hợp đừng quên từ chối quyền truy cập vào mọi thứ ngoại trừ

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
6. Nếu nó không thể được thực hiện, hãy xem xét việc lưu trữ ứng dụng của bạn ở nơi khác.

Trong chế độ gỡ lỗi, YII cho thấy các lỗi khá dài dòng, chắc chắn rất hữu ích cho sự phát triển. Vấn đề là các lỗi dài dòng này cũng tiện dụng cho kẻ tấn công vì chúng có thể tiết lộ cấu trúc cơ sở dữ liệu, giá trị cấu hình và các phần của mã của bạn. Không bao giờ chạy các ứng dụng sản xuất với

// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
9 được đặt thành
function actionList($orderBy = null)
{
    if (!in_array($orderBy, ['name', 'status'])) {
        throw new BadRequestHttpException('Only name and status are allowed to order by.')
    }
    
    // ...
}
0 trong
// query builder
$userIDs = (new Query())
    ->select('id')
    ->from('user')
    ->where('status=:status', [':status' => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand('SELECT id FROM user where status=:status')
    ->bindValues([':status' => $status])
    ->queryColumn();
7 của bạn.

  • Bạn không bao giờ nên kích hoạt Gii hoặc thanh công cụ gỡ lỗi trong sản xuất. Nó có thể được sử dụng để có được thông tin về cấu trúc cơ sở dữ liệu, mã và chỉ cần viết lại mã với những gì được tạo bởi GII.
  • Apache.
  • IIS.
  • Lighttpd.

Thanh công cụ gỡ lỗi nên tránh trong sản xuất trừ khi thực sự cần thiết. Nó phơi bày tất cả các chi tiết ứng dụng và cấu hình có thể. Nếu bạn hoàn toàn cần nó, hãy kiểm tra hai lần rằng quyền truy cập chỉ được giới hạn đúng cho IP của bạn.When TLS is configured it is recommended that (session) cookies are sent over TLS exclusively. This is achieved by setting the

function actionList($orderBy = null)
{
    if (!in_array($orderBy, ['name', 'status'])) {
        throw new BadRequestHttpException('Only name and status are allowed to order by.')
    }
    
    // ...
}
2 flag for sessions and/or cookies. See the Sessions and Cookies secure flag for more information.

https://owasp.org/www-pdf-archive/owasp_top_10_2007.pdf (A6-rò rỉ thông tin và xử lý lỗi không đúng)

Sử dụng kết nối an toàn qua TLS ¶

YII cung cấp các tính năng dựa vào cookie và/hoặc phiên PHP. Đây có thể dễ bị tổn thương trong trường hợp kết nối của bạn bị xâm phạm. Rủi ro sẽ giảm nếu ứng dụng sử dụng kết nối an toàn thông qua TLS (thường được gọi là SSL).

Để biết thêm thông tin về cấu hình máy chủ, vui lòng tham khảo tài liệu của máy chủ web của bạn:

  • Apache 2: https://httpd.apache.org/docs/trunk/vhosts/examples.html#defaultallports
  • Nginx: https://www.nginx.com/resource/wiki/start/topics/examples/server_blocks/

Nếu bạn không có quyền truy cập vào cấu hình máy chủ, bạn có thể thiết lập bộ lọc yii \ brilter \ hostcontrol ở cấp ứng dụng để bảo vệ chống lại loại tấn công đó:

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
1

Lưu ý: Bạn phải luôn thích cấu hình máy chủ web để bảo vệ 'Attack tiêu đề' của máy chủ 'thay vì sử dụng bộ lọc. Yii \ Bộ lọc \ HostControl chỉ nên được sử dụng nếu thiết lập cấu hình máy chủ không khả dụng.you should always prefer web server configuration for 'host header attack' protection instead of the filter usage. yii\filters\HostControl should be used only if server configuration setup is unavailable.

Định cấu hình xác thực ngang hàng SSL ¶

Có một quan niệm sai lầm điển hình về cách giải quyết các vấn đề xác nhận chứng chỉ SSL như:

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
2

hoặc

$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
3

Nhiều nguồn nhầm gợi ý tắt xác minh ngang hàng SSL. Điều đó không nên được thực hiện vì nó cho phép các loại tấn công giữa trong số các cuộc tấn công. Thay vào đó, PHP nên được cấu hình đúng cách:

  1. Tải xuống https://curl.haxx.se/ca/cacert.pem.
  2. Thêm phần sau vào php.ini của bạn:
    function actionList($orderBy = null)
    {
        if (!in_array($orderBy, ['name', 'status'])) {
            throw new BadRequestHttpException('Only name and status are allowed to order by.')
        }
        
        // ...
    }
    
    5

Lưu ý rằng tệp

function actionList($orderBy = null)
{
    if (!in_array($orderBy, ['name', 'status'])) {
        throw new BadRequestHttpException('Only name and status are allowed to order by.')
    }
    
    // ...
}
6 nên được cập nhật.